// DnsFirewallThread.cpp : implementation file
//

#include "stdafx.h"
#include "WS2InterceptDLL.h"
#include "DnsResorceRecord.h"
#include "DnsMessageWB.h"
#include "DnsStateThread.h"
#include "DnsFirewallThread.h"
#include "Trace.h"
#include "DnsFirewallThread.tmh"


// CDnsFirewallThread

IMPLEMENT_DYNCREATE(CDnsFirewallThread, CWinThread)

CDnsFirewallThread::CDnsFirewallThread()
: m_pMainStateThread(NULL)
, m_nThreadIndex(-1)
, m_nRetCode(0)
, m_oThreadInitEvent(FALSE,TRUE)
, m_hIoCompletionPort(NULL)
{
    int     i;
    m_bAutoDelete = FALSE;
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        m_aFileHandleArray[i] = INVALID_HANDLE_VALUE;
    }
    RtlZeroMemory(
        m_aFowContextArray,
        sizeof(m_aFowContextArray)
        );
    RtlZeroMemory(
        m_aWaitFlowDoneOverlapedArray,
        sizeof(m_aWaitFlowDoneOverlapedArray)
        );
    RtlZeroMemory(
        m_aWaitDnsQueryOverlapedArray,
        sizeof(m_aWaitDnsQueryOverlapedArray)
        );
    RtlZeroMemory(
        m_aWaitUdpQuery2OverlappedArray,
        sizeof(m_aWaitUdpQuery2OverlappedArray)
        );
    RtlZeroMemory(
        m_aWaitUdpSetFilterOverlappedArray,
        sizeof(m_aWaitUdpSetFilterOverlappedArray)
        );
    RtlZeroMemory(
        m_aDnsQueryMessage,
        sizeof(m_aDnsQueryMessage)
        );
    RtlZeroMemory(
        m_aAbortedQuery,
        sizeof(m_aAbortedQuery)
        );
    RtlZeroMemory(
        m_aWaitTcpResponceOverlapped,
        sizeof(m_aWaitTcpResponceOverlapped)
        );
    RtlZeroMemory(
        m_aWaitTcpNewMessageOverlapped,
        sizeof(m_aWaitTcpNewMessageOverlapped)
        );
    RtlZeroMemory(
        m_aZoneTransferMessage,
        sizeof(m_aZoneTransferMessage)
        );
}

CDnsFirewallThread::~CDnsFirewallThread()
{
}

BOOL CDnsFirewallThread::InitInstance()
{
    BOOL        bRet;
    int         i, j;
    CString     sDnsFirewallFileName;
    DWORD       dwResult;
    ULONG_PTR   ulCompletionKey;
    HANDLE      hIoCompletionPort;
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNS_FIREWALL_THREAD,
        "%!FUNC! line:%!LINE! %!LEVEL! Enter"
        );
    _tsetlocale(LC_ALL, _T("Russian"));
    if (NULL == m_pMainStateThread)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == m_pMainStateThread)"
            );
        m_nRetCode = -1;
        return FALSE;
    }
    if (m_nThreadIndex < 0)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (m_nThreadIndex < 0)"
            );
        m_nRetCode = -1;
        return FALSE;
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        sDnsFirewallFileName.Format(
            _T("%s\\$%d@%d"),
            DNSFIREWALL_DOS_NAME,
            m_nThreadIndex,
            i
            );
        m_aFileHandleArray[i] = CreateFileW(
            sDnsFirewallFileName,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_FLAG_OVERLAPPED,
            NULL
            );
        if (INVALID_HANDLE_VALUE == m_aFileHandleArray[i])
        {
            dwResult = ::GetLastError();
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Error opening the file DNS packets filter. Error: %!WINERROR!",
                dwResult
                );
            m_nRetCode = dwResult;
            return FALSE;
        }
    }
    m_hIoCompletionPort = theApp.m_pfSavedCreateIoCompletionPortFunction(
        INVALID_HANDLE_VALUE,
        NULL,
        0,
        0
        );
    if (NULL == m_hIoCompletionPort)
    {
        dwResult = ::GetLastError();
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Error on create IO Complete Port. Error: %!WINERROR!",
            dwResult
            );
        m_nRetCode = dwResult;
        return FALSE;
    }
    else
    {
        TraceEvents(
            TRACE_LEVEL_INFORMATION,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Created Io Completion Port = %p",
            (void*) m_hIoCompletionPort
            );
    }
    j = m_nThreadIndex + 1;
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        ulCompletionKey = (ULONG_PTR(j) << 32) + i;
        hIoCompletionPort = theApp.m_pfSavedCreateIoCompletionPortFunction(
            m_aFileHandleArray[i],
            m_hIoCompletionPort,
            ulCompletionKey,
            0
            );
        if (NULL == hIoCompletionPort)
        {
            dwResult = ::GetLastError();
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Error on associate IO Complete Port = %p with file handle = %p. Error: %!WINERROR!; ulCompletionKey = %p;",
                (void*) m_hIoCompletionPort,
                (void*) m_aFileHandleArray[i],
                dwResult,
                (void*) ulCompletionKey
                );
            m_nRetCode = dwResult;
            return FALSE;
        }
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        RtlZeroMemory(
            &m_aWaitFlowDoneOverlapedArray[i],
            sizeof(OVERLAPPED)
            );
        bRet = DeviceIoControl(
            m_aFileHandleArray[i],
            DNSFIREWALL_IOCTL_WAIT_FLOW_DONE,
            NULL,
            0,
            &m_aFowContextArray[i],
            sizeof(FLOW_DATA),
            &dwResult,
            &m_aWaitFlowDoneOverlapedArray[i]
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS flow Done. Error: %!WINERROR!",
                    dwResult
                    );
                m_nRetCode = dwResult;
                return FALSE;
            }
        }
        else
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS flow Done must be PENDING. Dns File #%d;",
                i
                );
            m_nRetCode = ERROR_INVALID_HANDLE_STATE;
            return FALSE;
        }
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        RtlZeroMemory(
            &m_aWaitUdpQuery2OverlappedArray[i],
            sizeof(OVERLAPPED)
            );
        bRet = DeviceIoControl(
            m_aFileHandleArray[i],
            DNSFIREWALL_IOCTL_WAIT_UDP_QUERY2,
            NULL,
            0,
            &m_aFowContextArray[i],
            sizeof(FLOW_DATA),
            &dwResult,
            &m_aWaitUdpQuery2OverlappedArray[i]
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                dwResult = ::GetLastError();
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query failed to start. Error: %!WINERROR!; nFileIndex = %d;",
                    dwResult,
                    i
                    );
                m_nRetCode = dwResult;
                return FALSE;
            }
        }
        else
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query must be PENDING. nFileIndex = %d;",
                i
                );
            m_nRetCode = ERROR_INVALID_HANDLE_STATE;
            return FALSE;
        }
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        RtlZeroMemory(
            &m_aWaitUdpSetFilterOverlappedArray[i],
            sizeof(OVERLAPPED)
            );
        bRet = DeviceIoControl(
            m_aFileHandleArray[i],
            DNSFIREWALL_IOCTL_WAIT_UDP_SET_FILTER,
            NULL,
            0,
            &m_aFowContextArray[i],
            sizeof(FLOW_DATA),
            &dwResult,
            &m_aWaitUdpSetFilterOverlappedArray[i]
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                dwResult = ::GetLastError();
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter failed to start. Error: %!WINERROR!; nFileIndex = %d;",
                    dwResult,
                    i
                    );
                m_nRetCode = dwResult;
                return FALSE;
            }
        }
        else
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter must be PENDING. nFileIndex = %d;",
                i
                );
            m_nRetCode = ERROR_INVALID_HANDLE_STATE;
            return FALSE;
        }
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        RtlZeroMemory(
            &m_aWaitDnsQueryOverlapedArray[i],
            sizeof(OVERLAPPED)
            );
        bRet = DeviceIoControl(
            m_aFileHandleArray[i],
            DNSFIREWALL_IOCTL_WAIT_DNS_QUERY,
            NULL,
            0,
            &m_aFowContextArray[i],
            sizeof(FLOW_DATA),
            &dwResult,
            &m_aWaitDnsQueryOverlapedArray[i]
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                dwResult = ::GetLastError();
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS query. Error: %!WINERROR!",
                    dwResult
                    );
                m_nRetCode = dwResult;
                return FALSE;
            }
        }
        else
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS guery must be PENDING. Dns File #%d;",
                i
                );
            m_nRetCode = ERROR_INVALID_HANDLE_STATE;
            return FALSE;
        }
    }
    bRet = m_oThreadInitEvent.SetEvent();
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNS_FIREWALL_THREAD,
        "%!FUNC! line:%!LINE! %!LEVEL! Exit"
        );
    return TRUE;
}

int CDnsFirewallThread::ExitInstance()
{
    int             nRetCode, i;
    BOOL            bRet;
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNS_FIREWALL_THREAD,
        "%!FUNC! line:%!LINE! %!LEVEL! Enter"
        );
    nRetCode = CWinThread::ExitInstance();
    if (m_nRetCode < 0)
    {
        bRet = m_pMainStateThread->m_oThreadLock.Lock();
        m_pMainStateThread->m_bServiceRebootNeed = true;
        bRet = m_pMainStateThread->m_oThreadLock.Unlock();
    }
    for (i = 0; i < DNSFIREWALL_FILE_COUNT; i++)
    {
        if ((NULL != m_aFileHandleArray[i]) && (INVALID_HANDLE_VALUE != m_aFileHandleArray[i]))
        {
            bRet = CloseHandle(m_aFileHandleArray[i]);
            m_aFileHandleArray[i] = INVALID_HANDLE_VALUE;
        }
        if (NULL != m_aDnsQueryMessage[i])
        {
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! DnsQueryMessage entry not Empty. i = %d;",
                i
                );
            delete m_aDnsQueryMessage[i];
            m_aDnsQueryMessage[i] = NULL;
        }
        if (NULL != m_aZoneTransferMessage[i])
        {
            delete m_aZoneTransferMessage[i];
            m_aZoneTransferMessage[i] = NULL;
        }
    }
    if (NULL != m_hIoCompletionPort)
    {
        bRet = CloseHandle(m_hIoCompletionPort);
        m_hIoCompletionPort = NULL;
    }
    TraceEvents(
        TRACE_LEVEL_INFORMATION,
        TRACE_DNS_FIREWALL_THREAD,
        "%!FUNC! line:%!LINE! %!LEVEL! Exit"
        );
    return m_nRetCode;
}

BEGIN_MESSAGE_MAP(CDnsFirewallThread, CWinThread)
END_MESSAGE_MAP()


// CDnsFirewallThread message handlers


BOOL CDnsFirewallThread::OnIdle(LONG lCount)
{
    BOOL                bRet;
    DWORD               dwResult;
    ULONG_PTR           ulCompletionKey;
    LPOVERLAPPED        pOverlapped;
    DWORD               dwError;
    int                 nFileIndex, nFileQEntryIndex;
    HANDLE              hFileHandle;
    PFLOW_DATA          pFlowContext;
    TCHAR               szIpAddress[128];
    LPTSTR              pAddressEnd;
    IN_ADDR             stIpAddress;
    IN6_ADDR            stIp6Address;
    BYTE                baDnsQueryBuffer[4000];
    DNS_APPROVAL_OUTPUT stDnsApprovalOutput;
    CDnsMessageWB*      pDnsQueryMessage = NULL;
    CEvent              oOverlappedEvent(FALSE, TRUE);
    bool                bEof = false;
    BYTE                baDnsResponceBuffer[0x10000];
    ULONG               ulNumEntriesRemoved, i;
    NTSTATUS            status;
    lCount;
    dwError = ERROR_SUCCESS;
    bRet = GetQueuedCompletionStatusEx(
        m_hIoCompletionPort,
        m_aCompletionPortEntries,
        DNSFIREWALL_COMPLETION_ENTRIES_COUNT,
        &ulNumEntriesRemoved,
        1000,
        FALSE
        );
    if (!bRet)
    {
        dwError = GetLastError();
        if (ERROR_ABANDONED_WAIT_0 == dwError)
        {
            TraceEvents(
                TRACE_LEVEL_ERROR,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! IO Completion Port was closed"
                );
            m_nRetCode = dwError;
            bRet = PostThreadMessage(
                WM_QUIT,
                m_nRetCode,
                0
                );
            return FALSE;
        }
        if (WAIT_TIMEOUT == dwError)
        {
            return TRUE;
        }
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetQueuedCompletionStatusEx\" failed with error %!WINERROR!;",
            dwError
            );
        m_nRetCode = dwError;
        bRet = PostThreadMessage(
            WM_QUIT,
            m_nRetCode,
            0
            );
        return FALSE;
    }
    for (i = 0; i < ulNumEntriesRemoved; i++)
    {
        ulCompletionKey = m_aCompletionPortEntries[i].lpCompletionKey;
        pOverlapped = m_aCompletionPortEntries[i].lpOverlapped;
        nFileQEntryIndex = int(ulCompletionKey >> 32) - 1;
        nFileIndex = int(ulCompletionKey & 0xFFFFFFFF);
        hFileHandle = m_aFileHandleArray[nFileIndex];
        status = NTSTATUS(pOverlapped->Internal);
        bEof = (STATUS_END_OF_FILE == status);
        if (pOverlapped == &m_aWaitUdpSetFilterOverlappedArray[nFileIndex])
        {
            if (bEof)
            {
                continue;
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error on Set Filter operation. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    status,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = status;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            pFlowContext = &m_aFowContextArray[nFileIndex];
            //bRet = m_pMainStateThread->m_oTimersLock.Lock();
            if (pFlowContext->bIPv6)
            {
                m_pMainStateThread->ResetFirewallIpV6Config(pFlowContext->stRemoteAddressV6);
            }
            else
            {
                if (0 == pFlowContext->nRemoteAddressV4)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Remote IP4 Address is 0. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                m_pMainStateThread->ResetFirewallIpV4Config(pFlowContext->nRemoteAddressV4);
            }
            //bRet = m_pMainStateThread->m_oTimersLock.Unlock();
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_GET_FLOW_STATUS,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                NULL
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error on \"Get Flow Status\". Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    dwResult,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = dwResult;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            if (csWaitQueryStarted == pFlowContext->enContextState)
            {
                continue;
            }
            RtlZeroMemory(
                &m_aWaitFlowDoneOverlapedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_FLOW_DONE,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitFlowDoneOverlapedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS flow Done. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS flow Done must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitUdpQuery2OverlappedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_UDP_QUERY2,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitUdpQuery2OverlappedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitUdpSetFilterOverlappedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_UDP_SET_FILTER,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitUdpSetFilterOverlappedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitDnsQueryOverlapedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_DNS_QUERY,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitDnsQueryOverlapedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS guery must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            continue;
        }
        if (pOverlapped == &m_aWaitFlowDoneOverlapedArray[nFileIndex])
        {
            if (!bEof)
            {
                if (STATUS_NO_MORE_ENTRIES == status)
                {
                    continue;
                }
                if (!NT_SUCCESS(status))
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error on Wait Flow Done operation. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        status,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = status;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            pFlowContext = &m_aFowContextArray[nFileIndex];
            RtlZeroMemory(
                &m_aWaitFlowDoneOverlapedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_FLOW_DONE,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitFlowDoneOverlapedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS flow Done. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS flow Done must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitUdpQuery2OverlappedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_UDP_QUERY2,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitUdpQuery2OverlappedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP second query must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitUdpSetFilterOverlappedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_UDP_SET_FILTER,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitUdpSetFilterOverlappedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP set firewall filter must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &m_aWaitDnsQueryOverlapedArray[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_DNS_QUERY,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitDnsQueryOverlapedArray[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error launching operations to wait for DNS query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Operation to wait for DNS guery must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            continue;
        }
        if (pOverlapped == &m_aWaitDnsQueryOverlapedArray[nFileIndex])
        {
            if (bEof)
            {
                continue;
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error getting DNS query. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    status,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = status;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            pFlowContext = &m_aFowContextArray[nFileIndex];
            if (IPPROTO_UDP == pFlowContext->enIpProto)
            {
                DWORD               dwUdpDataSize = pFlowContext->ulUdpQueryDataLength;
                WORD                wDnsLength = (WORD) dwUdpDataSize;
                bool                bQueryParsed;
                UDP_QUERY_APPROVAL  stUdpQueryApproval;
                OVERLAPPED          stUdpQueryApprovalOverlapped;
                PDNS_HEADER         pDnsHeader;
                if (pFlowContext->bIPv6)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToString(
                        &stIp6Address,
                        szIpAddress
                        );
                }
                else
                {
                    stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                    pAddressEnd = RtlIpv4AddressToString(
                        &stIpAddress,
                        szIpAddress
                        );
                }
                RtlZeroMemory(
                    &stUdpQueryApproval,
                    sizeof(stUdpQueryApproval)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_READ_UDP_QUERY,
                    NULL,
                    0,
                    baDnsQueryBuffer,
                    dwUdpDataSize,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS UDP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                pDnsHeader = (PDNS_HEADER) baDnsQueryBuffer;
                if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
                {
                    RtlZeroMemory(
                        &stUdpQueryApprovalOverlapped,
                        sizeof(stUdpQueryApprovalOverlapped)
                        );
                    stUdpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
                    stUdpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stUdpQueryApprovalOverlapped.hEvent) | 0x1);
                    stUdpQueryApproval._enApprovalAction = aaPermit;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY,
                        &stUdpQueryApproval,
                        sizeof(stUdpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        &stUdpQueryApprovalOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stUdpQueryApprovalOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                    }
                    if (STATUS_CANCELLED == stUdpQueryApprovalOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval was cancelled. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                pDnsQueryMessage = new CDnsMessageWB();
                RtlZeroMemory(
                    &stDnsApprovalOutput.m_stApprovalConfig,
                    sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                    );
                try
                {
                    bQueryParsed = pDnsQueryMessage->DnsQueryParse(
                        (PDNS_MESSAGE_BUFFER) baDnsQueryBuffer,
                        wDnsLength,
                        stDnsApprovalOutput.m_stApprovalConfig,
                        stDnsApprovalOutput.m_pData,
                        sizeof(stDnsApprovalOutput.m_pData)
                        );
                }
                catch (int nExeption)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Received UDP Query length of %u bytes from DnsFile #%d clent.port = %hu; %ws;",
                        dwResult,
                        nFileIndex,
                        pFlowContext->usRemotePort,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Exception #%d occurred when invoking \"DnsQueryParse\"",
                        nExeption
                        );
                    bQueryParsed = false;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = true;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = false;
                }
                delete pDnsQueryMessage;
                pDnsQueryMessage = NULL;
                if (stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard)
                {
                    stUdpQueryApproval._enApprovalAction = aaDiscard;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY,
                        &stUdpQueryApproval,
                        sizeof(stUdpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Error approval DNS UDP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                RtlZeroMemory(
                    &stUdpQueryApprovalOverlapped,
                    sizeof(stUdpQueryApprovalOverlapped)
                    );
                stUdpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
                stUdpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stUdpQueryApprovalOverlapped.hEvent) | 0x1);
                stUdpQueryApproval._enApprovalAction = aaPermit;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY,
                    &stUdpQueryApproval,
                    sizeof(stUdpQueryApproval),
                    NULL,
                    0,
                    &dwResult,
                    &stUdpQueryApprovalOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stUdpQueryApprovalOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                }
                if (STATUS_CANCELLED == stUdpQueryApprovalOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval was cancelled. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            // TCP
            {
                DWORD               nBufferLength = (DWORD) pFlowContext->nTcpQueryLength;
                WORD                wDnsLength;
                bool                bQueryParsed;
                TCP_QUERY_APPROVAL  stTcpQueryApproval;
                OVERLAPPED          stTcpQueryApprovalOverlapped;
                OVERLAPPED          stTcpQueryReplaceOverlapped;
                PDNS_HEADER         pDnsHeader;
                if (pFlowContext->bIPv6)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToString(
                        &stIp6Address,
                        szIpAddress
                        );
                }
                else
                {
                    stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                    pAddressEnd = RtlIpv4AddressToString(
                        &stIpAddress,
                        szIpAddress
                        );
                }
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_READ_TCP_QUERY,
                    NULL,
                    0,
                    baDnsQueryBuffer,
                    nBufferLength,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS TCP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                wDnsLength = RtlUshortByteSwap(*(PUSHORT) baDnsQueryBuffer);
                m_aDnsQueryMessage[nFileIndex] = new CDnsMessageWB();
                RtlZeroMemory(
                    &stTcpQueryApproval,
                    sizeof(stTcpQueryApproval)
                    );
                RtlZeroMemory(
                    &stDnsApprovalOutput.m_stApprovalConfig,
                    sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                    );
                pDnsHeader = (PDNS_HEADER) &baDnsQueryBuffer[2];
                if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
                {
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! This is NOTIFY Query; Host IP = %ws; clent.port = %hu;",
                        szIpAddress,
                        pFlowContext->usRemotePort
                        );
                }
                try
                {
                    bQueryParsed = m_aDnsQueryMessage[nFileIndex]->DnsQueryParse(
                        (PDNS_MESSAGE_BUFFER) &baDnsQueryBuffer[2],
                        wDnsLength,
                        stDnsApprovalOutput.m_stApprovalConfig,
                        &stDnsApprovalOutput.m_pData[2],
                        sizeof(stDnsApprovalOutput.m_pData) - 2
                        );
                }
                catch (int nExeption)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Received TCP Query length of %u bytes from DnsFile #%d clent.port = %hu; %ws;",
                        dwResult,
                        nFileIndex,
                        pFlowContext->usRemotePort,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Exception #%d occurred when invoking \"DnsQueryParse\"",
                        nExeption
                        );
                    bQueryParsed = false;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = true;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = false;
                }
                if (stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard)
                {
                    stTcpQueryApproval._enApprovalAction = aaDiscard;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,
                        &stTcpQueryApproval,
                        sizeof(stTcpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_aAbortedQuery[nFileIndex] = false;
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                    }
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                if (!bQueryParsed)
                {
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Non Parsed Query length=%u from Host %ws; clent.port = %hu;",
                        (UINT32) wDnsLength,
                        szIpAddress,
                        pFlowContext->usRemotePort
                        );
                }
                if (!stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify)
                {
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    RtlZeroMemory(
                        &m_aWaitTcpResponceOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_RESPONCE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpResponceOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation of TCP responce failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP responce must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpQueryApprovalOverlapped,
                        sizeof(stTcpQueryApprovalOverlapped)
                        );
                    stTcpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
                    stTcpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpQueryApprovalOverlapped.hEvent) | 0x1);
                    stTcpQueryApproval._enApprovalAction = aaPermit;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,
                        &stTcpQueryApproval,
                        sizeof(stTcpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        &stTcpQueryApprovalOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Failed to start the wait operation TCP request acknowledgement. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpQueryApprovalOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpQueryApprovalOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation confirmation TCP query was cancelled; nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                // m_bDataModify
                m_aAbortedQuery[nFileIndex] = true;
                RtlZeroMemory(
                    &m_aWaitTcpResponceOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                stTcpQueryApproval._enApprovalAction = aaModify;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_RESPONCE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpResponceOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation of TCP responce failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP responce must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,   // m_bDataModify
                    &stTcpQueryApproval,
                    sizeof(stTcpQueryApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                RtlZeroMemory(
                    &stTcpQueryReplaceOverlapped,
                    sizeof(stTcpQueryReplaceOverlapped)
                    );
                stTcpQueryReplaceOverlapped.hEvent = oOverlappedEvent;
                stTcpQueryReplaceOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpQueryReplaceOverlapped.hEvent) | 0x1);
                *(PWORD) stDnsApprovalOutput.m_pData = RtlUshortByteSwap(
                    (USHORT) stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_INJECT_TCP_QUERY,
                    stDnsApprovalOutput.m_pData,
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize + 2,
                    NULL,
                    0,
                    &dwResult,
                    &stTcpQueryReplaceOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Failed to start the replacement operation TCP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_aAbortedQuery[nFileIndex] = false;
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpQueryReplaceOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                if (STATUS_CANCELLED == stTcpQueryReplaceOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The TCP request replacement surgery has been cancelled; nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
            }
            continue;
        }
        if (pOverlapped == &m_aWaitUdpQuery2OverlappedArray[nFileIndex])
        {
            if (bEof)
            {
                continue;
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error getting DNS query 2. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    status,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = status;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            pFlowContext = &m_aFowContextArray[nFileIndex];
            DWORD               dwUdpDataSize = pFlowContext->ulUdpQuery2DataLength;
            WORD                wDnsLength = (WORD) dwUdpDataSize;
            bool                bQueryParsed;
            UDP_QUERY_APPROVAL  stUdpQueryApproval;
            OVERLAPPED          stUdpQueryApprovalOverlapped;
            PDNS_HEADER         pDnsHeader;
            if (pFlowContext->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowContext->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToString(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToString(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_READ_UDP_QUERY2,
                NULL,
                0,
                baDnsQueryBuffer,
                dwUdpDataSize,
                &dwResult,
                NULL
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS UDP query 2. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                continue;
            }
            pDnsHeader = (PDNS_HEADER) baDnsQueryBuffer;
            if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
            {
                RtlZeroMemory(
                    &stUdpQueryApprovalOverlapped,
                    sizeof(stUdpQueryApprovalOverlapped)
                    );
                stUdpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
                stUdpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stUdpQueryApprovalOverlapped.hEvent) | 0x1);
                stUdpQueryApproval._enApprovalAction = aaPermit;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY,
                    &stUdpQueryApproval,
                    sizeof(stUdpQueryApproval),
                    NULL,
                    0,
                    &dwResult,
                    &stUdpQueryApprovalOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stUdpQueryApprovalOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                }
                if (STATUS_CANCELLED == stUdpQueryApprovalOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval was cancelled. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            pDnsQueryMessage = new CDnsMessageWB();
            RtlZeroMemory(
                &stDnsApprovalOutput.m_stApprovalConfig,
                sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                );
            try
            {
                bQueryParsed = pDnsQueryMessage->DnsQueryParse(
                    (PDNS_MESSAGE_BUFFER) baDnsQueryBuffer,
                    wDnsLength,
                    stDnsApprovalOutput.m_stApprovalConfig,
                    stDnsApprovalOutput.m_pData,
                    sizeof(stDnsApprovalOutput.m_pData)
                    );
            }
            catch (int nExeption)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Received UDP Query 2 length of %u bytes from DnsFile #%d clent.port = %hu; %ws;",
                    dwResult,
                    nFileIndex,
                    pFlowContext->usRemotePort,
                    szIpAddress
                    );
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Exception #%d occurred when invoking \"DnsQueryParse\"",
                    nExeption
                    );
                bQueryParsed = false;
                stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = true;
                stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = false;
            }
            delete pDnsQueryMessage;
            pDnsQueryMessage = NULL;
            if (stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard)
            {
                stUdpQueryApproval._enApprovalAction = aaDiscard;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY2,
                    &stUdpQueryApproval,
                    sizeof(stUdpQueryApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Error discard DNS UDP query 2. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            RtlZeroMemory(
                &stUdpQueryApprovalOverlapped,
                sizeof(stUdpQueryApprovalOverlapped)
                );
            stUdpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
            stUdpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stUdpQueryApprovalOverlapped.hEvent) | 0x1);
            stUdpQueryApproval._enApprovalAction = aaPermit;
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_APPROVAL_UDP_QUERY2,
                &stUdpQueryApproval,
                sizeof(stUdpQueryApproval),
                NULL,
                0,
                &dwResult,
                &stUdpQueryApprovalOverlapped
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
            }
            bRet = GetOverlappedResult(
                hFileHandle,
                &stUdpQueryApprovalOverlapped,
                &dwResult,
                TRUE
                );
            if (!bRet)
            {  // ERROR_CANCELLED
                dwResult = ::GetLastError();
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! UDP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                continue;
            }
            if (STATUS_CANCELLED == stUdpQueryApprovalOverlapped.Internal)
            {
                dwResult = ERROR_CANCELLED;
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for UDP query approval was cancelled. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                continue;
            }
            continue;
        }
        if (pOverlapped == &m_aWaitTcpResponceOverlapped[nFileIndex])
        {
            pFlowContext = &m_aFowContextArray[nFileIndex];
            if (bEof)
            {
                if (NULL != m_aDnsQueryMessage[nFileIndex])
                {
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                }
                m_aAbortedQuery[nFileIndex] = false;
                continue;
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error getting TCP DNS responce. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    status,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = status;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            DWORD                   nBufferLength;
            WORD                    wDnsLength;
            DWORD                   dwTcpDataSize;
            bool                    bMessageParsed = false;
            CDnsMessageWB*          pDnsMessage;
            CDnsResorceRecord*      pAddedRR;
            OVERLAPPED              stTcpResponceApprovalOverlapped;
            OVERLAPPED              stTcpResponceInjectOverlapped;
            TCP_RESPONCE_APPROVAL   stTcpResponceApproval;
            PDNS_HEADER             pDnsHeader;
            if (pFlowContext->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowContext->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToString(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToString(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            nBufferLength = (DWORD) pFlowContext->nTcpResponceLength;
            dwTcpDataSize = nBufferLength - 2;
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_READ_TCP_RESPONCE,
                NULL,
                0,
                baDnsResponceBuffer,
                nBufferLength,
                &dwResult,
                NULL
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS TCP responce. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                if (NULL != m_aDnsQueryMessage[nFileIndex])
                {
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                }
                m_aAbortedQuery[nFileIndex] = false;
                continue;
            }
            wDnsLength = RtlUshortByteSwap(*(PUSHORT) baDnsResponceBuffer);
            assert(wDnsLength == (WORD) dwTcpDataSize);
            RtlZeroMemory(
                &stDnsApprovalOutput.m_stApprovalConfig,
                sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                );
            RtlZeroMemory(
                &stTcpResponceApproval,
                sizeof(stTcpResponceApproval)
                );
            pDnsHeader = (PDNS_HEADER) &baDnsResponceBuffer[2];
            if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
            {
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                RtlZeroMemory(
                    &stTcpResponceApprovalOverlapped,
                    sizeof(stTcpResponceApprovalOverlapped)
                    );
                stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
                stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
                stTcpResponceApproval._enApprovalAction = aaPermit;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    &stTcpResponceApprovalOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpResponceApprovalOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                            dwResult
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            pDnsMessage = new CDnsMessageWB;
            assert(NULL != pDnsMessage);
            bMessageParsed = pDnsMessage->ParseDnsMessageBuffer(
                (PDNS_MESSAGE_BUFFER) &baDnsResponceBuffer[2],
                wDnsLength
                );
            if (!bMessageParsed)
            {
                // ïîäòâåðæäåíèå îòïðàâêè êëèåíòó îòâåòíîãî ñîîáùåíèÿ áåç RR èëè ñ êîäîì îòâåòà îòëè÷íîì îò íóëÿ,
                // à òàêæå îòâåòà íà çàïðîñ îáðàòíîãî ïîèñêà
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Send confirmation to the customer problem response TCP message. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                    szIpAddress,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                RtlZeroMemory(
                    &stTcpResponceApprovalOverlapped,
                    sizeof(stTcpResponceApprovalOverlapped)
                    );
                stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
                stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
                stTcpResponceApproval._enApprovalAction = aaPermit;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    &stTcpResponceApprovalOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpResponceApprovalOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                            dwResult
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    if (NULL != m_aDnsQueryMessage[nFileIndex])
                    {
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                    }
                    m_aAbortedQuery[nFileIndex] = false;
                    continue;
                }
                if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    if (NULL != m_aDnsQueryMessage[nFileIndex])
                    {
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                    }
                    m_aAbortedQuery[nFileIndex] = false;
                    continue;
                }
                if (NULL != m_aDnsQueryMessage[nFileIndex])
                {
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                }
                m_aAbortedQuery[nFileIndex] = false;
                continue;
            }
            // bMessageParsed
            if (m_aAbortedQuery[nFileIndex])
            {
                // îòâåðæåíèå íåîáðàáàòûâàåìîãî çàïðîñà
                UINT32              nMessageLength;
                CDnsResorceRecord*  pSoaRRecord = NULL;
                CDnsResorceRecord*  pCurrentRR;
                CDnsResorceRecord*  pNextRR;
                assert(DNS_TYPE_SOA == pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType);
                pCurrentRR = pDnsMessage->m_pFirstDnsRRecord;
                while (NULL != pCurrentRR)
                {
                    pNextRR = pCurrentRR->m_pNext;
                    if (DnsSectionQuestion != pDnsMessage->m_pLastDnsRRecord->m_unDnsRecordFlags.S.Section)
                    {
                        if (DNS_TYPE_SOA == pCurrentRR->m_wType)
                        {
                            pSoaRRecord = pCurrentRR;
                            pSoaRRecord->m_unDnsRecordFlags.S.Section = DnsSectionAuthority;
                            pDnsMessage->RemoveRRAt(pCurrentRR);
                        }
                        else
                        {
                            pDnsMessage->RemoveRRAt(pCurrentRR);
                            delete pCurrentRR;
                        }
                    }
                    pCurrentRR = pNextRR;
                }
                assert(NULL != pSoaRRecord);
                if ((DNS_OPCODE_QUERY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode)
                    || (DNS_OPCODE_IQUERY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode)
                    || (DNS_OPCODE_NOTIFY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode))
                {
                    pDnsMessage->m_stDnsHeader.ResponseCode = DNS_RCODE_NOTIMPL;
                    pDnsMessage->AddRRToTail(pSoaRRecord);
                    nMessageLength = pDnsMessage->PerformDnsMessageBuffer(
                        &stDnsApprovalOutput.m_pData[2],
                        sizeof(stDnsApprovalOutput.m_pData) - 2
                        );
                }
                else
                { // !(DNS_OPCODE_QUERY == m_pDnsQueryMessage->m_stDnsHeader.Opcode)
                    pDnsMessage->m_stDnsHeader.ResponseCode = DNS_RCODE_NOTIMPL;
                    pDnsMessage->m_stDnsHeader.Opcode = m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode;
                    pDnsMessage->AddRRToTail(pSoaRRecord);
                    nMessageLength = pDnsMessage->PerformDnsMessageBuffer(
                        &stDnsApprovalOutput.m_pData[2],
                        sizeof(stDnsApprovalOutput.m_pData) - 2
                        );
                }
                delete pDnsMessage;
                delete m_aDnsQueryMessage[nFileIndex];
                m_aDnsQueryMessage[nFileIndex] = NULL;
                m_aAbortedQuery[nFileIndex] = false;
                stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize = nMessageLength;
                stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = TRUE;
                wDnsLength = (WORD) nMessageLength;
                stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize += 2;
                INLINE_WORD_FLIP(*((PWORD) stDnsApprovalOutput.m_pData), wDnsLength);
                stTcpResponceApproval._enApprovalAction = aaModify;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                RtlZeroMemory(
                    &stTcpResponceInjectOverlapped,
                    sizeof(stTcpResponceInjectOverlapped)
                    );
                stTcpResponceInjectOverlapped.hEvent = oOverlappedEvent;
                stTcpResponceInjectOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceInjectOverlapped.hEvent) | 0x1);
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
                    stDnsApprovalOutput.m_pData,
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize,
                    NULL,
                    0,
                    &dwResult,
                    &stTcpResponceInjectOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpResponceInjectOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                            dwResult
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                if (STATUS_CANCELLED == stTcpResponceInjectOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            // (!m_bAbortedQuery) && TCP
            if (DNS_TYPE_AXFR == pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType)
            {
                // îòâåðæåíèå çàäåðæàííîãî îòâåòíîãî ñîîáùåíèÿ
                // (QuestionType == DNS_TYPE_AXFR) && (!m_bAbortedQuery) && TCP
                bool    bSuccessfull;
                stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = TRUE;
                stTcpResponceApproval._enApprovalAction = aaDiscard;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                if (NULL != m_aZoneTransferMessage[nFileIndex])
                {
                    while ((pAddedRR = pDnsMessage->RemoveFromHeader()) != NULL)
                    {
                        m_aZoneTransferMessage[nFileIndex]->AddRRToTail(pAddedRR);
                        if (DNS_TYPE_SOA == pAddedRR->m_wType)
                        {
                            break;
                        }
                    }
                    delete pDnsMessage;
                    if (NULL == pAddedRR)
                    {
                        continue;
                    }
                    if (DNS_TYPE_SOA != pAddedRR->m_wType)
                    {
                        continue;
                    }
                    bSuccessfull = ReCreateZoneTransferMessage(
                        hFileHandle,
                        pFlowContext,
                        m_aZoneTransferMessage[nFileIndex],
                        &dwResult
                        );
                    delete m_aZoneTransferMessage[nFileIndex];
                    m_aZoneTransferMessage[nFileIndex] = NULL;
                    if (!bSuccessfull)
                    {
                        if (ERROR_HANDLE_EOF == dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone unexpectedly Terminated. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                        if (ERROR_CANCELLED == dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone was cancelled. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Assembly response message transfer DNS zone has error = %!WINERROR!. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    continue;
                }
                // NULL == m_pZoneTransferMessage
                assert(DNS_TYPE_SOA == pDnsMessage->m_pFirstDnsRRecord->m_wType);
                m_aZoneTransferMessage[nFileIndex] = pDnsMessage;
                if (1 == pDnsMessage->m_nAnswerCount)
                {
                    continue;
                }
                if (DNS_TYPE_SOA != pDnsMessage->m_pLastDnsRRecord->m_wType)
                {
                    continue;
                }
                bSuccessfull = ReCreateZoneTransferMessage(
                    hFileHandle,
                    pFlowContext,
                    m_aZoneTransferMessage[nFileIndex],
                    &dwResult
                    );
                delete pDnsMessage;
                m_aZoneTransferMessage[nFileIndex] = NULL;
                if (!bSuccessfull)
                {
                    if (ERROR_HANDLE_EOF == dwResult)
                    {
                        //TraceEvents(
                        //    TRACE_LEVEL_WARNING,
                        //    TRACE_DNS_FIREWALL_THREAD,
                        //    "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone unexpectedly Terminated. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        //    szIpAddress,
                        //    nFileIndex,
                        //    nFileQEntryIndex
                        //    );
                        continue;
                    }
                    if (ERROR_CANCELLED == dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone was cancelled. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Assembly response message transfer DNS zone has error = %!WINERROR!. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        dwResult,
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                // bSuccessfull
                continue;
            }
            // DNS_TYPE_AXFR != pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType
            // îáðàáîòêà îòâåòíîãî ñîîáùåíèÿ îòëè÷íîãî îò ñîîáùåíèÿ ïðåäà÷è DNS-çîíû
            pDnsMessage->DnsReParseResponceMessage(
                stDnsApprovalOutput.m_stApprovalConfig,
                &stDnsApprovalOutput.m_pData[2],
                sizeof(stDnsApprovalOutput.m_pData) - 2
                );
            delete pDnsMessage;
            if (stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify)
            {
                wDnsLength = (WORD) stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize;
                stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize += 2;
                INLINE_WORD_FLIP(*((PWORD) stDnsApprovalOutput.m_pData), wDnsLength);
                stTcpResponceApproval._enApprovalAction = aaModify;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                RtlZeroMemory(
                    &stTcpResponceInjectOverlapped,
                    sizeof(stTcpResponceInjectOverlapped)
                    );
                stTcpResponceInjectOverlapped.hEvent = oOverlappedEvent;
                stTcpResponceInjectOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceInjectOverlapped.hEvent) | 0x1);
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
                    stDnsApprovalOutput.m_pData,
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize,
                    NULL,
                    0,
                    &dwResult,
                    &stTcpResponceInjectOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpResponceInjectOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                            dwResult
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                if (STATUS_CANCELLED == stTcpResponceInjectOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            // (DNS_TYPE_AXFR != xxx.QuestionType)&&(!m_bDataModify)
            RtlZeroMemory(
                &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                sizeof(OVERLAPPED)
                );
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                NULL,
                0,
                pFlowContext,
                sizeof(FLOW_DATA),
                &dwResult,
                &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
            }
            else
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                    szIpAddress,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = -1;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            RtlZeroMemory(
                &stTcpResponceApprovalOverlapped,
                sizeof(stTcpResponceApprovalOverlapped)
                );
            stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
            stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
            stTcpResponceApproval._enApprovalAction = aaPermit;
            bRet = DeviceIoControl(
                hFileHandle,
                DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                &stTcpResponceApproval,
                sizeof(stTcpResponceApproval),
                NULL,
                0,
                &dwResult,
                &stTcpResponceApprovalOverlapped
                );
            if (!bRet)
            {
                dwResult = ::GetLastError();
                if (ERROR_IO_PENDING != dwResult)
                {
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
            }
            bRet = GetOverlappedResult(
                hFileHandle,
                &stTcpResponceApprovalOverlapped,
                &dwResult,
                TRUE
                );
            if (!bRet)
            {  // ERROR_CANCELLED
                dwResult = ::GetLastError();
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                        dwResult
                        );
                    m_nRetCode = dwResult;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                TraceEvents(
                    TRACE_LEVEL_WARNING,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                    nFileIndex,
                    nFileQEntryIndex
                    );
                continue;
            }
            if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
            {
                dwResult = ERROR_CANCELLED;
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                    szIpAddress,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                continue;
            }
            continue;
        }
        if (pOverlapped == &m_aWaitTcpNewMessageOverlapped[nFileIndex])
        {
            pFlowContext = &m_aFowContextArray[nFileIndex];
            if (bEof)
            {
                if (NULL != m_aDnsQueryMessage[nFileIndex])
                {
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                }
                m_aAbortedQuery[nFileIndex] = false;
                continue;
            }
            if (!NT_SUCCESS(status))
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Error getting New TCP DNS message. Status: %!STATUS!; nFileIndex = %d; nFileQEntryIndex = %d;",
                    status,
                    nFileIndex,
                    nFileQEntryIndex
                    );
                m_nRetCode = status;
                bRet = PostThreadMessage(
                    WM_QUIT,
                    m_nRetCode,
                    0
                    );
                return FALSE;
            }
            DWORD                   nBufferLength;
            WORD                    wDnsLength;
            bool                    bQueryParsed;
            DWORD                   dwTcpDataSize;
            bool                    bMessageParsed = false;
            CDnsMessageWB*          pDnsMessage;
            CDnsResorceRecord*      pAddedRR;
            OVERLAPPED              stTcpResponceApprovalOverlapped;
            OVERLAPPED              stTcpResponceInjectOverlapped;
            TCP_RESPONCE_APPROVAL   stTcpResponceApproval;
            PDNS_HEADER             pDnsHeader;
            if (pFlowContext->bIPv6)
            {
                RtlCopyMemory(
                    &stIp6Address,
                    &pFlowContext->stRemoteAddressV6,
                    sizeof(stIp6Address)
                    );
                pAddressEnd = RtlIpv6AddressToString(
                    &stIp6Address,
                    szIpAddress
                    );
            }
            else
            {
                stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                pAddressEnd = RtlIpv4AddressToString(
                    &stIpAddress,
                    szIpAddress
                    );
            }
            if (FWP_DIRECTION_OUTBOUND == pFlowContext->enPacketDirection)
            {
                nBufferLength = (DWORD) pFlowContext->nTcpResponceLength;
                dwTcpDataSize = nBufferLength - 2;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_READ_TCP_RESPONCE,
                    NULL,
                    0,
                    baDnsResponceBuffer,
                    nBufferLength,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS TCP responce. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    if (NULL != m_aDnsQueryMessage[nFileIndex])
                    {
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                    }
                    m_aAbortedQuery[nFileIndex] = false;
                    continue;
                }
                wDnsLength = RtlUshortByteSwap(*(PUSHORT) baDnsResponceBuffer);
                assert(wDnsLength == (WORD) dwTcpDataSize);
                RtlZeroMemory(
                    &stDnsApprovalOutput.m_stApprovalConfig,
                    sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                    );
                RtlZeroMemory(
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval)
                    );
                pDnsHeader = (PDNS_HEADER) &baDnsResponceBuffer[2];
                if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
                {
                    RtlZeroMemory(
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpResponceApprovalOverlapped,
                        sizeof(stTcpResponceApprovalOverlapped)
                        );
                    stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
                    stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
                    stTcpResponceApproval._enApprovalAction = aaPermit;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                        &stTcpResponceApproval,
                        sizeof(stTcpResponceApproval),
                        NULL,
                        0,
                        &dwResult,
                        &stTcpResponceApprovalOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpResponceApprovalOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                                dwResult
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                pDnsMessage = new CDnsMessageWB;
                assert(NULL != pDnsMessage);
                bMessageParsed = pDnsMessage->ParseDnsMessageBuffer(
                    (PDNS_MESSAGE_BUFFER) &baDnsResponceBuffer[2],
                    wDnsLength
                    );
                if (!bMessageParsed)
                {
                    // ïîäòâåðæäåíèå îòïðàâêè êëèåíòó îòâåòíîãî ñîîáùåíèÿ áåç RR èëè ñ êîäîì îòâåòà îòëè÷íîì îò íóëÿ,
                    // à òàêæå îòâåòà íà çàïðîñ îáðàòíîãî ïîèñêà
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Send confirmation to the customer problem response TCP message. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    RtlZeroMemory(
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            if (NULL != m_aDnsQueryMessage[nFileIndex])
                            {
                                delete m_aDnsQueryMessage[nFileIndex];
                                m_aDnsQueryMessage[nFileIndex] = NULL;
                            }
                            m_aAbortedQuery[nFileIndex] = false;
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpResponceApprovalOverlapped,
                        sizeof(stTcpResponceApprovalOverlapped)
                        );
                    stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
                    stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
                    stTcpResponceApproval._enApprovalAction = aaPermit;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                        &stTcpResponceApproval,
                        sizeof(stTcpResponceApproval),
                        NULL,
                        0,
                        &dwResult,
                        &stTcpResponceApprovalOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            if (NULL != m_aDnsQueryMessage[nFileIndex])
                            {
                                delete m_aDnsQueryMessage[nFileIndex];
                                m_aDnsQueryMessage[nFileIndex] = NULL;
                            }
                            m_aAbortedQuery[nFileIndex] = false;
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpResponceApprovalOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                                dwResult
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                    continue;
                }
                // bMessageParsed
                if (m_aAbortedQuery[nFileIndex])
                {
                    // îòâåðæåíèå íåîáðàáàòûâàåìîãî çàïðîñà
                    UINT32              nMessageLength;
                    CDnsResorceRecord*  pSoaRRecord = NULL;
                    CDnsResorceRecord*  pCurrentRR;
                    CDnsResorceRecord*  pNextRR;
                    assert(DNS_TYPE_SOA == pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType);
                    pCurrentRR = pDnsMessage->m_pFirstDnsRRecord;
                    while (NULL != pCurrentRR)
                    {
                        pNextRR = pCurrentRR->m_pNext;
                        if (DnsSectionQuestion != pDnsMessage->m_pLastDnsRRecord->m_unDnsRecordFlags.S.Section)
                        {
                            if (DNS_TYPE_SOA == pCurrentRR->m_wType)
                            {
                                pSoaRRecord = pCurrentRR;
                                pSoaRRecord->m_unDnsRecordFlags.S.Section = DnsSectionAuthority;
                                pDnsMessage->RemoveRRAt(pCurrentRR);
                            }
                            else
                            {
                                pDnsMessage->RemoveRRAt(pCurrentRR);
                                delete pCurrentRR;
                            }
                        }
                        pCurrentRR = pNextRR;
                    }
                    assert(NULL != pSoaRRecord);
                    if ((DNS_OPCODE_QUERY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode)
                        || (DNS_OPCODE_IQUERY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode)
                        || (DNS_OPCODE_NOTIFY == m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode))
                    {
                        pDnsMessage->m_stDnsHeader.ResponseCode = DNS_RCODE_NOTIMPL;
                        pDnsMessage->AddRRToTail(pSoaRRecord);
                        nMessageLength = pDnsMessage->PerformDnsMessageBuffer(
                            &stDnsApprovalOutput.m_pData[2],
                            sizeof(stDnsApprovalOutput.m_pData) - 2
                            );
                    }
                    else
                    { // !(DNS_OPCODE_QUERY == m_pDnsQueryMessage->m_stDnsHeader.Opcode)
                        pDnsMessage->m_stDnsHeader.ResponseCode = DNS_RCODE_NOTIMPL;
                        pDnsMessage->m_stDnsHeader.Opcode = m_aDnsQueryMessage[nFileIndex]->m_stDnsHeader.Opcode;
                        pDnsMessage->AddRRToTail(pSoaRRecord);
                        nMessageLength = pDnsMessage->PerformDnsMessageBuffer(
                            &stDnsApprovalOutput.m_pData[2],
                            sizeof(stDnsApprovalOutput.m_pData) - 2
                            );
                    }
                    delete pDnsMessage;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    m_aAbortedQuery[nFileIndex] = false;
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize = nMessageLength;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = TRUE;
                    wDnsLength = (WORD) nMessageLength;
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize += 2;
                    INLINE_WORD_FLIP(*((PWORD) stDnsApprovalOutput.m_pData), wDnsLength);
                    stTcpResponceApproval._enApprovalAction = aaModify;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                        &stTcpResponceApproval,
                        sizeof(stTcpResponceApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    RtlZeroMemory(
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpResponceInjectOverlapped,
                        sizeof(stTcpResponceInjectOverlapped)
                        );
                    stTcpResponceInjectOverlapped.hEvent = oOverlappedEvent;
                    stTcpResponceInjectOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceInjectOverlapped.hEvent) | 0x1);
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
                        stDnsApprovalOutput.m_pData,
                        stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize,
                        NULL,
                        0,
                        &dwResult,
                        &stTcpResponceInjectOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpResponceInjectOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                                dwResult
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpResponceInjectOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                // (!m_bAbortedQuery) && TCP
                if (DNS_TYPE_AXFR == pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType)
                {
                    // îòâåðæåíèå çàäåðæàííîãî îòâåòíîãî ñîîáùåíèÿ
                    // (QuestionType == DNS_TYPE_AXFR) && (!m_bAbortedQuery) && TCP
                    bool    bSuccessfull;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = TRUE;
                    stTcpResponceApproval._enApprovalAction = aaDiscard;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                        &stTcpResponceApproval,
                        sizeof(stTcpResponceApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    RtlZeroMemory(
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    if (NULL != m_aZoneTransferMessage[nFileIndex])
                    {
                        while ((pAddedRR = pDnsMessage->RemoveFromHeader()) != NULL)
                        {
                            m_aZoneTransferMessage[nFileIndex]->AddRRToTail(pAddedRR);
                            if (DNS_TYPE_SOA == pAddedRR->m_wType)
                            {
                                break;
                            }
                        }
                        delete pDnsMessage;
                        if (NULL == pAddedRR)
                        {
                            continue;
                        }
                        if (DNS_TYPE_SOA != pAddedRR->m_wType)
                        {
                            continue;
                        }
                        bSuccessfull = ReCreateZoneTransferMessage(
                            hFileHandle,
                            pFlowContext,
                            m_aZoneTransferMessage[nFileIndex],
                            &dwResult
                            );
                        delete m_aZoneTransferMessage[nFileIndex];
                        m_aZoneTransferMessage[nFileIndex] = NULL;
                        if (!bSuccessfull)
                        {
                            if (ERROR_HANDLE_EOF == dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_WARNING,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone unexpectedly Terminated. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                continue;
                            }
                            if (ERROR_CANCELLED == dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_WARNING,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone was cancelled. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                continue;
                            }
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Assembly response message transfer DNS zone has error = %!WINERROR!. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        continue;
                    }
                    // NULL == m_pZoneTransferMessage[nFileIndex]
                    assert(DNS_TYPE_SOA == pDnsMessage->m_pFirstDnsRRecord->m_wType);
                    m_aZoneTransferMessage[nFileIndex] = pDnsMessage;
                    if (1 == pDnsMessage->m_nAnswerCount)
                    {
                        continue;
                    }
                    if (DNS_TYPE_SOA != pDnsMessage->m_pLastDnsRRecord->m_wType)
                    {
                        continue;
                    }
                    bSuccessfull = ReCreateZoneTransferMessage(
                        hFileHandle,
                        pFlowContext,
                        m_aZoneTransferMessage[nFileIndex],
                        &dwResult
                        );
                    delete pDnsMessage;
                    m_aZoneTransferMessage[nFileIndex] = NULL;
                    if (!bSuccessfull)
                    {
                        if (ERROR_HANDLE_EOF == dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone unexpectedly Terminated. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                        if (ERROR_CANCELLED == dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Response message transfer DNS zone was cancelled. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Assembly response message transfer DNS zone has error = %!WINERROR!. IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    // bSuccessfull
                    continue;
                }
                // DNS_TYPE_AXFR != pDnsMessage->m_stDnsQuestionRecord.stDnsWireQuestion.QuestionType
                // îáðàáîòêà îòâåòíîãî ñîîáùåíèÿ îòëè÷íîãî îò ñîîáùåíèÿ ïðåäà÷è DNS-çîíû
                pDnsMessage->DnsReParseResponceMessage(
                    stDnsApprovalOutput.m_stApprovalConfig,
                    &stDnsApprovalOutput.m_pData[2],
                    sizeof(stDnsApprovalOutput.m_pData) - 2
                    );
                delete pDnsMessage;
                if (stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify)
                {
                    wDnsLength = (WORD) stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize;
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize += 2;
                    INLINE_WORD_FLIP(*((PWORD) stDnsApprovalOutput.m_pData), wDnsLength);
                    stTcpResponceApproval._enApprovalAction = aaModify;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                        &stTcpResponceApproval,
                        sizeof(stTcpResponceApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    RtlZeroMemory(
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpResponceInjectOverlapped,
                        sizeof(stTcpResponceInjectOverlapped)
                        );
                    stTcpResponceInjectOverlapped.hEvent = oOverlappedEvent;
                    stTcpResponceInjectOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceInjectOverlapped.hEvent) | 0x1);
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
                        stDnsApprovalOutput.m_pData,
                        stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize,
                        NULL,
                        0,
                        &dwResult,
                        &stTcpResponceInjectOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    szIpAddress,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpResponceInjectOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                                dwResult
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpResponceInjectOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                            szIpAddress,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                // (DNS_TYPE_AXFR != xxx.QuestionType)&&(!m_bDataModify)
                RtlZeroMemory(
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_NEW_MESSAGE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpNewMessageOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting a new TCP message. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for new TCP message must be PENDING; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                RtlZeroMemory(
                    &stTcpResponceApprovalOverlapped,
                    sizeof(stTcpResponceApprovalOverlapped)
                    );
                stTcpResponceApprovalOverlapped.hEvent = oOverlappedEvent;
                stTcpResponceApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpResponceApprovalOverlapped.hEvent) | 0x1);
                stTcpResponceApproval._enApprovalAction = aaPermit;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_RESPONCE,
                    &stTcpResponceApproval,
                    sizeof(stTcpResponceApproval),
                    NULL,
                    0,
                    &dwResult,
                    &stTcpResponceApprovalOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The start operation failed waiting TCP response. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                szIpAddress,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpResponceApprovalOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                            dwResult
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                if (STATUS_CANCELLED == stTcpResponceApprovalOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation TCP responce was cancelled; IP address = \"%ws\"; nFileIndex = %d; nFileQEntryIndex = %d;",
                        szIpAddress,
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                continue;
            }
            // FWP_DIRECTION_INBOUND
            {
                TCP_QUERY_APPROVAL  stTcpQueryApproval;
                OVERLAPPED          stTcpQueryApprovalOverlapped;
                OVERLAPPED          stTcpQueryReplaceOverlapped;
                DWORD               nBufferLength = (DWORD) pFlowContext->nTcpQueryLength;
                if (pFlowContext->bIPv6)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        &pFlowContext->stRemoteAddressV6,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToString(
                        &stIp6Address,
                        szIpAddress
                        );
                }
                else
                {
                    stIpAddress.S_un.S_addr = pFlowContext->nRemoteAddressV4N;
                    pAddressEnd = RtlIpv4AddressToString(
                        &stIpAddress,
                        szIpAddress
                        );
                }
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_READ_TCP_QUERY,
                    NULL,
                    0,
                    baDnsQueryBuffer,
                    nBufferLength,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Error reading DNS TCP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    continue;
                }
                wDnsLength = RtlUshortByteSwap(*(PUSHORT) baDnsQueryBuffer);
                m_aDnsQueryMessage[nFileIndex] = new CDnsMessageWB();
                RtlZeroMemory(
                    &stTcpQueryApproval,
                    sizeof(stTcpQueryApproval)
                    );
                RtlZeroMemory(
                    &stDnsApprovalOutput.m_stApprovalConfig,
                    sizeof(stDnsApprovalOutput.m_stApprovalConfig)
                    );
                pDnsHeader = (PDNS_HEADER) &baDnsQueryBuffer[2];
                if (DNS_OPCODE_NOTIFY == pDnsHeader->Opcode)
                {
                    TraceEvents(
                        TRACE_LEVEL_INFORMATION,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! This is NOTIFY Query; Host IP = %ws; clent.port = %hu;",
                        szIpAddress,
                        pFlowContext->usRemotePort
                        );
                }
                try
                {
                    bQueryParsed = m_aDnsQueryMessage[nFileIndex]->DnsQueryParse(
                        (PDNS_MESSAGE_BUFFER) &baDnsQueryBuffer[2],
                        wDnsLength,
                        stDnsApprovalOutput.m_stApprovalConfig,
                        &stDnsApprovalOutput.m_pData[2],
                        sizeof(stDnsApprovalOutput.m_pData) - 2
                        );
                }
                catch (int nExeption)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Received TCP Query length of %u bytes from DnsFile #%d clent.port = %hu; %ws;",
                        dwResult,
                        nFileIndex,
                        pFlowContext->usRemotePort,
                        szIpAddress
                        );
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Exception #%d occurred when invoking \"DnsQueryParse\"",
                        nExeption
                        );
                    bQueryParsed = false;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard = true;
                    stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify = false;
                }
                if (stDnsApprovalOutput.m_stApprovalConfig.m_bDiscard)
                {
                    stTcpQueryApproval._enApprovalAction = aaDiscard;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,
                        &stTcpQueryApproval,
                        sizeof(stTcpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        NULL
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_aAbortedQuery[nFileIndex] = false;
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                    }
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                if (!bQueryParsed)
                {
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Non Parsed Query length=%u from Host %ws; clent.port = %hu;",
                        (UINT32) wDnsLength,
                        szIpAddress,
                        pFlowContext->usRemotePort
                        );
                }
                if (!stDnsApprovalOutput.m_stApprovalConfig.m_bDataModify)
                {
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    RtlZeroMemory(
                        &m_aWaitTcpResponceOverlapped[nFileIndex],
                        sizeof(OVERLAPPED)
                        );
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_WAIT_TCP_RESPONCE,
                        NULL,
                        0,
                        pFlowContext,
                        sizeof(FLOW_DATA),
                        &dwResult,
                        &m_aWaitTcpResponceOverlapped[nFileIndex]
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! The wait operation of TCP responce failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    else
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP responce must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_nRetCode = -1;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    RtlZeroMemory(
                        &stTcpQueryApprovalOverlapped,
                        sizeof(stTcpQueryApprovalOverlapped)
                        );
                    stTcpQueryApprovalOverlapped.hEvent = oOverlappedEvent;
                    stTcpQueryApprovalOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpQueryApprovalOverlapped.hEvent) | 0x1);
                    stTcpQueryApproval._enApprovalAction = aaPermit;
                    bRet = DeviceIoControl(
                        hFileHandle,
                        DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,
                        &stTcpQueryApproval,
                        sizeof(stTcpQueryApproval),
                        NULL,
                        0,
                        &dwResult,
                        &stTcpQueryApprovalOverlapped
                        );
                    if (!bRet)
                    {
                        dwResult = ::GetLastError();
                        if (ERROR_IO_PENDING != dwResult)
                        {
                            if (ERROR_HANDLE_EOF != dwResult)
                            {
                                TraceEvents(
                                    TRACE_LEVEL_ERROR,
                                    TRACE_DNS_FIREWALL_THREAD,
                                    "%!FUNC! line:%!LINE! %!LEVEL! Failed to start the wait operation TCP request acknowledgement. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                    dwResult,
                                    nFileIndex,
                                    nFileQEntryIndex
                                    );
                                m_nRetCode = dwResult;
                                bRet = PostThreadMessage(
                                    WM_QUIT,
                                    m_nRetCode,
                                    0
                                    );
                                return FALSE;
                            }
                            TraceEvents(
                                TRACE_LEVEL_WARNING,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            continue;
                        }
                    }
                    bRet = GetOverlappedResult(
                        hFileHandle,
                        &stTcpQueryApprovalOverlapped,
                        &dwResult,
                        TRUE
                        );
                    if (!bRet)
                    {  // ERROR_CANCELLED
                        dwResult = ::GetLastError();
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    if (STATUS_CANCELLED == stTcpQueryApprovalOverlapped.Internal)
                    {
                        dwResult = ERROR_CANCELLED;
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation confirmation TCP query was cancelled; nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        continue;
                    }
                    continue;
                }
                // m_bDataModify
                m_aAbortedQuery[nFileIndex] = true;
                RtlZeroMemory(
                    &m_aWaitTcpResponceOverlapped[nFileIndex],
                    sizeof(OVERLAPPED)
                    );
                stTcpQueryApproval._enApprovalAction = aaModify;
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_WAIT_TCP_RESPONCE,
                    NULL,
                    0,
                    pFlowContext,
                    sizeof(FLOW_DATA),
                    &dwResult,
                    &m_aWaitTcpResponceOverlapped[nFileIndex]
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! The wait operation of TCP responce failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        if (NULL != m_aDnsQueryMessage[nFileIndex])
                        {
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                        }
                        m_aAbortedQuery[nFileIndex] = false;
                        continue;
                    }
                }
                else
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP responce must be PENDING. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_nRetCode = -1;
                    bRet = PostThreadMessage(
                        WM_QUIT,
                        m_nRetCode,
                        0
                        );
                    return FALSE;
                }
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_APPROVAL_TCP_QUERY,
                    &stTcpQueryApproval,
                    sizeof(stTcpQueryApproval),
                    NULL,
                    0,
                    &dwResult,
                    NULL
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! The wait operation for TCP query approval failed to start. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                RtlZeroMemory(
                    &stTcpQueryReplaceOverlapped,
                    sizeof(stTcpQueryReplaceOverlapped)
                    );
                stTcpQueryReplaceOverlapped.hEvent = oOverlappedEvent;
                stTcpQueryReplaceOverlapped.hEvent = HANDLE(ULONG_PTR(stTcpQueryReplaceOverlapped.hEvent) | 0x1);
                *(PWORD) stDnsApprovalOutput.m_pData = RtlUshortByteSwap(
                    (USHORT) stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize
                    );
                bRet = DeviceIoControl(
                    hFileHandle,
                    DNSFIREWALL_IOCTL_INJECT_TCP_QUERY,
                    stDnsApprovalOutput.m_pData,
                    stDnsApprovalOutput.m_stApprovalConfig.m_nDataSize + 2,
                    NULL,
                    0,
                    &dwResult,
                    &stTcpQueryReplaceOverlapped
                    );
                if (!bRet)
                {
                    dwResult = ::GetLastError();
                    if (ERROR_IO_PENDING != dwResult)
                    {
                        if (ERROR_HANDLE_EOF != dwResult)
                        {
                            TraceEvents(
                                TRACE_LEVEL_ERROR,
                                TRACE_DNS_FIREWALL_THREAD,
                                "%!FUNC! line:%!LINE! %!LEVEL! Failed to start the replacement operation TCP query. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                                dwResult,
                                nFileIndex,
                                nFileQEntryIndex
                                );
                            m_aAbortedQuery[nFileIndex] = false;
                            delete m_aDnsQueryMessage[nFileIndex];
                            m_aDnsQueryMessage[nFileIndex] = NULL;
                            m_nRetCode = dwResult;
                            bRet = PostThreadMessage(
                                WM_QUIT,
                                m_nRetCode,
                                0
                                );
                            return FALSE;
                        }
                        TraceEvents(
                            TRACE_LEVEL_WARNING,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        continue;
                    }
                }
                bRet = GetOverlappedResult(
                    hFileHandle,
                    &stTcpQueryReplaceOverlapped,
                    &dwResult,
                    TRUE
                    );
                if (!bRet)
                {  // ERROR_CANCELLED
                    dwResult = ::GetLastError();
                    if (ERROR_HANDLE_EOF != dwResult)
                    {
                        TraceEvents(
                            TRACE_LEVEL_ERROR,
                            TRACE_DNS_FIREWALL_THREAD,
                            "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!; nFileIndex = %d; nFileQEntryIndex = %d;",
                            dwResult,
                            nFileIndex,
                            nFileQEntryIndex
                            );
                        m_aAbortedQuery[nFileIndex] = false;
                        delete m_aDnsQueryMessage[nFileIndex];
                        m_aDnsQueryMessage[nFileIndex] = NULL;
                        m_nRetCode = dwResult;
                        bRet = PostThreadMessage(
                            WM_QUIT,
                            m_nRetCode,
                            0
                            );
                        return FALSE;
                    }
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! TCP Flow was Deleted. nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
                if (STATUS_CANCELLED == stTcpQueryReplaceOverlapped.Internal)
                {
                    dwResult = ERROR_CANCELLED;
                    TraceEvents(
                        TRACE_LEVEL_WARNING,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! The TCP request replacement surgery has been cancelled; nFileIndex = %d; nFileQEntryIndex = %d;",
                        nFileIndex,
                        nFileQEntryIndex
                        );
                    m_aAbortedQuery[nFileIndex] = false;
                    delete m_aDnsQueryMessage[nFileIndex];
                    m_aDnsQueryMessage[nFileIndex] = NULL;
                    continue;
                }
            }
            continue;
        }
    }
    return TRUE;
}


bool CDnsFirewallThread::ReCreateZoneTransferMessage(
    HANDLE hFileHandle,
    PFLOW_DATA pFlowData,
    CDnsMessageWB* pZoneTransferMessage,
    DWORD* pErrorCode
    )
{
    CDnsResorceRecord*  pCurrentRR = pZoneTransferMessage->m_pFirstDnsRRecord;
    CDnsResorceRecord*  pNextRR;
    UINT32      nBufferLength;
    int         nA4Count = 0;
    int         nA4PrivateCount = 0;
    int         nA6Count = 0;
    int         nA6PrivateCount = 0;
    TCP_INJECT_OUTPUT   stTcpInjectOutput;
    OVERLAPPED  stInjectResponceDoneOverlapped;
    CEvent      oOverlappedEvent(FALSE, TRUE);
    TCHAR       szIpAddress[128];
    LPTSTR      pAddressEnd;
    IN_ADDR     stIpAddress;
    IN6_ADDR    stIp6Address;
    BOOL        bRet;
    DWORD       dwResult, dwOverlappedResult;
    *pErrorCode = 0;
    if (NULL == pCurrentRR)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (NULL == pCurrentRR)"
            );
        *pErrorCode = DWORD(-1);
        return false;
    }
    pNextRR = pCurrentRR->m_pNext;
    if (DNS_TYPE_SOA != pCurrentRR->m_wType)
    {
        TraceEvents(
            TRACE_LEVEL_ERROR,
            TRACE_DNS_FIREWALL_THREAD,
            "%!FUNC! line:%!LINE! %!LEVEL! Exit (DNS_TYPE_SOA != pCurrentRR->m_wType)"
            );
        *pErrorCode = DWORD(-1);
        return false;
    }
    GetPtrAddressesInfo(
        pZoneTransferMessage,
        pCurrentRR,
        CString(pCurrentRR->m_pDnsRecordData->SOA.pNamePrimaryServer),
        nA4Count,
        nA4PrivateCount,
        nA6Count,
        nA6PrivateCount
        );
    if (IsPrivate(nA4Count, nA4PrivateCount, nA6Count, nA6PrivateCount))
    {
        while (NULL != pZoneTransferMessage->m_pLastDnsRRecord)
        {
            pCurrentRR = pZoneTransferMessage->RemoveFromTail();
            delete pCurrentRR;
        }
        pZoneTransferMessage->AddRRToTail(new CDnsResorceRecord(*theApp.m_pDnsZoneRecord));
        pZoneTransferMessage->m_stDnsHeader.ResponseCode = DNS_RCODE_NXDOMAIN;
        nBufferLength = pZoneTransferMessage->PerformDnsMessageBuffer(
            stTcpInjectOutput.m_pData,
            (UINT32)sizeof(stTcpInjectOutput.m_pData)
            );
        stTcpInjectOutput.m_wMessageLength = (WORD) nBufferLength;
        INLINE_HTONS(stTcpInjectOutput.m_wMessageLength, stTcpInjectOutput.m_wMessageLength);
        nBufferLength += 2;
        RtlZeroMemory(
            &stInjectResponceDoneOverlapped,
            sizeof(stInjectResponceDoneOverlapped)
            );
        stInjectResponceDoneOverlapped.hEvent = oOverlappedEvent;
        stInjectResponceDoneOverlapped.hEvent = HANDLE(ULONG_PTR(stInjectResponceDoneOverlapped.hEvent) | 0x1);
        bRet = DeviceIoControl(
            hFileHandle,
            DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
            &stTcpInjectOutput.m_wMessageLength,
            nBufferLength,
            NULL,
            0,
            &dwResult,
            &stInjectResponceDoneOverlapped
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                if (pFlowData->bIPv6)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        &pFlowData->stRemoteAddressV6,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToString(
                        &stIp6Address,
                        szIpAddress
                        );
                }
                else
                {
                    stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                    pAddressEnd = RtlIpv4AddressToString(
                        &stIpAddress,
                        szIpAddress
                        );
                }
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d;",
                        dwResult,
                        szIpAddress,
                        pFlowData->nFileIndex
                        );
                }
                *pErrorCode = dwResult;
                return false;
            }
        }
        bRet = GetOverlappedResult(
            hFileHandle,
            &stInjectResponceDoneOverlapped,
            &dwOverlappedResult,
            TRUE
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_HANDLE_EOF != dwResult)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                    dwResult
                    );
            }
            *pErrorCode = dwResult;
            return false;
        }
        if (STATUS_CANCELLED == stInjectResponceDoneOverlapped.Internal)
        {
            dwResult = ERROR_CANCELLED;
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Insert operation DNS response was cancelled. ; IP address = \"%ws\"; nFileIndex = %d;",
                szIpAddress,
                pFlowData->nFileIndex
                );
            *pErrorCode = dwResult;
            return false;
        }
        return true;
    }
    pCurrentRR = pNextRR;
    // 1-ïðîõîä -- èñêëþ÷åíèå ÷èñòî ëîêàëüíûõ ññûëîê, WINS è WINSR çàïèñåé
    while (NULL != pCurrentRR)
    {
        int     nA4Count = 0;
        int     nA4PrivateCount = 0;
        int     nA6Count = 0;
        int     nA6PrivateCount = 0;
        CString sTargetName;
        pNextRR = pCurrentRR->m_pNext;
        if ((DNS_TYPE_WINS == pCurrentRR->m_wType) || (DNS_TYPE_WINSR == pCurrentRR->m_wType))
        {
            pZoneTransferMessage->RemoveRRAt(pCurrentRR);
            delete pCurrentRR;
        }
        else
        {
            switch (pCurrentRR->m_wType)
            {
            case DNS_TYPE_SOA:
                sTargetName = pCurrentRR->m_pDnsRecordData->SOA.pNamePrimaryServer;
                break;
            case DNS_TYPE_PTR:
            case DNS_TYPE_NS:
            case DNS_TYPE_CNAME:
            case DNS_TYPE_DNAME:
            case DNS_TYPE_MB:
            case DNS_TYPE_MD:
            case DNS_TYPE_MF:
            case DNS_TYPE_MG:
            case DNS_TYPE_MR:
                sTargetName = pCurrentRR->m_pDnsRecordData->PTR.pNameHost;
                break;
            case DNS_TYPE_MX:
            case DNS_TYPE_AFSDB:
            case DNS_TYPE_RT:
            case DNS_TYPE_KX:
                sTargetName = pCurrentRR->m_pDnsRecordData->MX.pNameExchange;
                break;
            case DNS_TYPE_SIG:
            case DNS_TYPE_RRSIG:
                sTargetName = pCurrentRR->m_pDnsRecordData->SIG.pNameSigner;
                break;
            case DNS_TYPE_NXT:
            case DNS_TYPE_NSEC:
                sTargetName = pCurrentRR->m_pDnsRecordData->NSEC.pNextDomainName;
                break;
            case DNS_TYPE_SRV:
                sTargetName = pCurrentRR->m_pDnsRecordData->SRV.pNameTarget;
                break;
            case DNS_TYPE_NAPTR:
                sTargetName = pCurrentRR->m_pDnsRecordData->NAPTR.pReplacement;
                break;
            case DNS_TYPE_TKEY:
                sTargetName = pCurrentRR->m_pDnsRecordData->TKEY.pNameAlgorithm;
                break;
            case DNS_TYPE_TSIG:
                sTargetName = pCurrentRR->m_pDnsRecordData->TSIG.pNameAlgorithm;
                break;
            }
            if (!sTargetName.IsEmpty())
            {
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    sTargetName,
                    nA4Count,
                    nA4PrivateCount,
                    nA6Count,
                    nA6PrivateCount
                    );
                if (IsPrivate(nA4Count, nA4PrivateCount, nA6Count, nA6PrivateCount))
                {
                    pZoneTransferMessage->RemoveRRAt(pCurrentRR);
                    delete pCurrentRR;
                }
            }
        }
        if (pNextRR == pZoneTransferMessage->m_pLastDnsRRecord)
        {
            break;
        }
        else
        {
            pCurrentRR = pNextRR;
        }
    }
    // 2-ïðîõîä -- èñêëþ÷åíèå ïðèâàòíûõ àäðåñîâ
    pCurrentRR = pZoneTransferMessage->m_pFirstDnsRRecord->m_pNext;
    while (NULL != pCurrentRR)
    {
        pNextRR = pCurrentRR->m_pNext;
        if (DNS_TYPE_AAAA == pCurrentRR->m_wType)
        {
            IN6_ADDR    stIPv6Address;
            BOOLEAN     bPrivate = FALSE;
            int         i;
            IPv6CopyAddress(
                &stIPv6Address,
                (const IP6_ADDRESS*) &pCurrentRR->m_pDnsRecordData->AAAA.Ip6Address
                );
            bPrivate = !bfIPv6AddressInIPv6Subnet(
                &stIPv6Address,
                c_pGlobalIPv6Subnet
                );
            if (!bPrivate)
            {
                for (i = 0; i<theApp.m_nPrivateIPV6AddrCount; i++)
                {
                    bPrivate = bfIPv6AddressInIPv6Subnet(
                        &stIPv6Address,
                        &theApp.m_pPrivateIPV6AddrArray[i]
                        );
                    if (bPrivate)
                    {
                        break;
                    }
                }
            }
            if (bPrivate)
            {
                BOOLEAN bPublic = FALSE;
                for (i = 0; i < theApp.m_nPublicIPV6AddrCount; i++)
                {
                    bPublic = bfIPv6AddressInIPv6Subnet(
                        &stIPv6Address,
                        &theApp.m_pPublicIPV6AddrArray[i]
                        );
                    if (bPublic)
                    {
                        break;
                    }
                }
                if (!bPublic)
                {
                    pZoneTransferMessage->RemoveRRAt(pCurrentRR);
                    delete pCurrentRR;
                }
            }
        }
        else
            if (DNS_TYPE_A == pCurrentRR->m_wType)
            {
                int     i;
                UINT32  nHostAddress = 0;
                bool    bPrivate = false;
                INLINE_NTOHL(
                    nHostAddress,
                    pCurrentRR->m_pDnsRecordData->A.IpAddress
                    );
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateIpCount; i++)
                    {
                        bPrivate = (nHostAddress == theApp.m_pPrivateIpArray[i]);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateRangeCount; i++)
                    {
                        bPrivate = (nHostAddress <= theApp.m_pPrivateRangeArray[i].valueHigh.uint32)
                            && (nHostAddress >= theApp.m_pPrivateRangeArray[i].valueLow.uint32);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateSubnetCount; i++)
                    {
                        bPrivate = ((nHostAddress & theApp.m_pPrivateSubnetArray[i].mask)
                            == theApp.m_pPrivateSubnetArray[i].addr);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (bPrivate)
                {
                    pZoneTransferMessage->RemoveRRAt(pCurrentRR);
                    delete pCurrentRR;
                }
            }
        pCurrentRR = pNextRR;
    }
    // 3-ïðîõîä -- ïåðäà÷à DNS-çîíû êëèåíòó
    while ((pCurrentRR = pZoneTransferMessage->RemoveFromHeader()) != NULL)
    {
        CDnsMessageWB oNewDnsMessage(
            pZoneTransferMessage,
            pCurrentRR
            );
        nBufferLength = oNewDnsMessage.PerformDnsMessageBuffer(
            stTcpInjectOutput.m_pData,
            (UINT32)sizeof(stTcpInjectOutput.m_pData)
            );
        stTcpInjectOutput.m_wMessageLength = (WORD) nBufferLength;
        INLINE_HTONS(stTcpInjectOutput.m_wMessageLength, stTcpInjectOutput.m_wMessageLength);
        nBufferLength += 2;
        stTcpInjectOutput.m_stInjectConfig.m_nDataSize = nBufferLength;
        RtlZeroMemory(
            &stInjectResponceDoneOverlapped,
            sizeof(stInjectResponceDoneOverlapped)
            );
        stInjectResponceDoneOverlapped.hEvent = oOverlappedEvent;
        stInjectResponceDoneOverlapped.hEvent = HANDLE(ULONG_PTR(stInjectResponceDoneOverlapped.hEvent) | 0x1);
        bRet = DeviceIoControl(
            hFileHandle,
            DNSFIREWALL_IOCTL_INJECT_TCP_RESPONCE,
            &stTcpInjectOutput.m_wMessageLength,
            nBufferLength,
            NULL,
            0,
            &dwResult,
            &stInjectResponceDoneOverlapped
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_IO_PENDING != dwResult)
            {
                if (pFlowData->bIPv6)
                {
                    RtlCopyMemory(
                        &stIp6Address,
                        &pFlowData->stRemoteAddressV6,
                        sizeof(stIp6Address)
                        );
                    pAddressEnd = RtlIpv6AddressToString(
                        &stIp6Address,
                        szIpAddress
                        );
                }
                else
                {
                    stIpAddress.S_un.S_addr = pFlowData->nRemoteAddressV4N;
                    pAddressEnd = RtlIpv4AddressToString(
                        &stIpAddress,
                        szIpAddress
                        );
                }
                if (ERROR_HANDLE_EOF != dwResult)
                {
                    TraceEvents(
                        TRACE_LEVEL_ERROR,
                        TRACE_DNS_FIREWALL_THREAD,
                        "%!FUNC! line:%!LINE! %!LEVEL! Error start operation of waiting to insert TCP responce. Error: %!WINERROR!; IP address = \"%ws\"; nFileIndex = %d;",
                        dwResult,
                        szIpAddress,
                        pFlowData->nFileIndex
                        );
                }
                *pErrorCode = dwResult;
                return false;
            }
        }
        bRet = GetOverlappedResult(
            hFileHandle,
            &stInjectResponceDoneOverlapped,
            &dwOverlappedResult,
            TRUE
            );
        if (!bRet)
        {
            dwResult = ::GetLastError();
            if (ERROR_HANDLE_EOF != dwResult)
            {
                TraceEvents(
                    TRACE_LEVEL_ERROR,
                    TRACE_DNS_FIREWALL_THREAD,
                    "%!FUNC! line:%!LINE! %!LEVEL! Call \"GetOverlappedResult\" failed. Error: %!WINERROR!",
                    dwResult
                    );
            }
            *pErrorCode = dwResult;
            return false;
        }
        if (STATUS_CANCELLED == stInjectResponceDoneOverlapped.Internal)
        {
            dwResult = ERROR_CANCELLED;
            TraceEvents(
                TRACE_LEVEL_WARNING,
                TRACE_DNS_FIREWALL_THREAD,
                "%!FUNC! line:%!LINE! %!LEVEL! Insert operation DNS response was cancelled. ; IP address = \"%ws\"; nFileIndex = %d;",
                szIpAddress,
                pFlowData->nFileIndex
                );
            *pErrorCode = dwResult;
            return false;
        }
    }
    return true;
}


void CDnsFirewallThread::GetPtrAddressesInfo(
    CDnsMessageWB* pZoneTransferMessage,
    CDnsResorceRecord* pSourceRR,
    CString sTargetDName,
    int& rA4Count,
    int& rA4PrivateCount,
    int& rA6Count,
    int& rA6PrivateCount
    )
{
    CDnsResorceRecord*  pCurrentRR = pZoneTransferMessage->m_pFirstDnsRRecord;
    CDnsResorceRecord*  pNextRR;
    while (NULL != pCurrentRR)
    {
        int     i;
        pNextRR = pCurrentRR->m_pNext;
        if ((pCurrentRR != pSourceRR)
            && DnsNameCompare(
            (LPCTSTR) sTargetDName,
            (LPCTSTR) pCurrentRR->m_sName
            )
            )
        {
            switch (pCurrentRR->m_wType)
            {
            case DNS_TYPE_A:
            {
                UINT32  nHostAddress = 0;
                bool    bPrivate = false;
                INLINE_NTOHL(
                    nHostAddress,
                    pCurrentRR->m_pDnsRecordData->A.IpAddress
                    );
                rA4Count++;
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateIpCount; i++)
                    {
                        bPrivate = (nHostAddress == theApp.m_pPrivateIpArray[i]);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateRangeCount; i++)
                    {
                        bPrivate = (nHostAddress <= theApp.m_pPrivateRangeArray[i].valueHigh.uint32)
                            && (nHostAddress >= theApp.m_pPrivateRangeArray[i].valueLow.uint32);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateSubnetCount; i++)
                    {
                        bPrivate = ((nHostAddress & theApp.m_pPrivateSubnetArray[i].mask)
                            == theApp.m_pPrivateSubnetArray[i].addr);
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (bPrivate)
                {
                    rA4PrivateCount++;
                }
            }
            break;
            case DNS_TYPE_AAAA:
            {
                IN6_ADDR    stIPv6Address;
                BOOLEAN     bPrivate = FALSE;
                IPv6CopyAddress(
                    &stIPv6Address,
                    (const IP6_ADDRESS*) &pCurrentRR->m_pDnsRecordData->AAAA.Ip6Address
                    );
                rA6Count++;
                bPrivate = !bfIPv6AddressInIPv6Subnet(
                    &stIPv6Address,
                    c_pGlobalIPv6Subnet
                    );
                if (!bPrivate)
                {
                    for (i = 0; i<theApp.m_nPrivateIPV6AddrCount; i++)
                    {
                        bPrivate = bfIPv6AddressInIPv6Subnet(
                            &stIPv6Address,
                            &theApp.m_pPrivateIPV6AddrArray[i]
                            );
                        if (bPrivate)
                        {
                            break;
                        }
                    }
                }
                if (bPrivate)
                {
                    BOOLEAN bPublic = FALSE;
                    for (i = 0; i < theApp.m_nPublicIPV6AddrCount; i++)
                    {
                        bPublic = bfIPv6AddressInIPv6Subnet(
                            &stIPv6Address,
                            &theApp.m_pPublicIPV6AddrArray[i]
                            );
                        if (bPublic)
                        {
                            break;
                        }
                    }
                    if (!bPublic)
                    {
                        rA6PrivateCount++;
                    }
                }
            }
            break;
            case DNS_TYPE_SOA:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->SOA.pNamePrimaryServer),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_PTR:
            case DNS_TYPE_NS:
            case DNS_TYPE_MD:
            case DNS_TYPE_MF:
            case DNS_TYPE_CNAME:
            case DNS_TYPE_MB:
            case DNS_TYPE_MG:
            case DNS_TYPE_MR:
            case DNS_TYPE_DNAME:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->CNAME.pNameHost),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_MX:
            case DNS_TYPE_AFSDB:
            case DNS_TYPE_RT:
            case DNS_TYPE_KX:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->MX.pNameExchange),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_SIG:
            case DNS_TYPE_RRSIG:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->SIG.pNameSigner),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_NXT:
            case DNS_TYPE_NSEC:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->NSEC.pNextDomainName),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_SRV:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->SRV.pNameTarget),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_NAPTR:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->NAPTR.pReplacement),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_TKEY:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->TKEY.pNameAlgorithm),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_TSIG:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->TSIG.pNameAlgorithm),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            case DNS_TYPE_WINSR:
                GetPtrAddressesInfo(
                    pZoneTransferMessage,
                    pCurrentRR,
                    CString(pCurrentRR->m_pDnsRecordData->WINSR.pNameResultDomain),
                    rA4Count,
                    rA4PrivateCount,
                    rA6Count,
                    rA6PrivateCount
                    );
                return;
            }
        }
        pCurrentRR = pNextRR;
    }
}
