915 lines
27 KiB
C++
915 lines
27 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998, Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dnsmsg.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code for the DNS proxy's message-processing.
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (aboladeg) 9-Mar-1998
|
||
|
||
Revision History:
|
||
|
||
Raghu Gatta (rgatta) 1-Dec-2000
|
||
Rewrite + Cleanup + New Functions
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
//
|
||
// EXTERNAL DECLARATIONS
|
||
//
|
||
extern "C" DWORD G_UseEdns;
|
||
|
||
|
||
VOID
|
||
DnsProcessQueryMessage(
|
||
PDNS_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to process a DNS query message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the query was received
|
||
|
||
Bufferp - the buffer containing the query
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked internally in the context of a worker-thread completion routine,
|
||
with an outstanding reference to 'Interfacep' from the time the
|
||
read-operation was begun.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Context;
|
||
PVOID Context2;
|
||
ULONG Error;
|
||
PDNS_QUERY Queryp;
|
||
PDNS_HEADER Headerp;
|
||
BOOLEAN Referenced = TRUE;
|
||
SOCKET Socket;
|
||
LPVOID lpMsgBuf;
|
||
|
||
PROFILE("DnsProcessQueryMessage");
|
||
|
||
#if DBG
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: dumping %d bytes",
|
||
Bufferp->BytesTransferred
|
||
);
|
||
|
||
NhDump(
|
||
TRACE_FLAG_DNS,
|
||
Bufferp->Buffer,
|
||
Bufferp->BytesTransferred,
|
||
1
|
||
);
|
||
|
||
#endif
|
||
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.QueriesReceived)
|
||
);
|
||
|
||
Headerp = (PDNS_HEADER)Bufferp->Buffer;
|
||
|
||
Socket = Bufferp->Socket;
|
||
Context = Bufferp->Context;
|
||
Context2 = Bufferp->Context2;
|
||
|
||
//
|
||
// if the Broadcast bit (9) was set, we leave it as is
|
||
// instead of zeroing it
|
||
//
|
||
//if (Headerp->Broadcast) {
|
||
// Headerp->Broadcast = 0;
|
||
//}
|
||
|
||
if (Headerp->Opcode == DNS_OPCODE_QUERY ||
|
||
Headerp->Opcode == DNS_OPCODE_IQUERY ||
|
||
Headerp->Opcode == DNS_OPCODE_SERVER_STATUS) {
|
||
|
||
//
|
||
// Query the local DNS Resolver cache before proxying
|
||
//
|
||
|
||
//
|
||
// Unpack
|
||
//
|
||
DNS_STATUS dnsStatus;
|
||
DNS_PARSED_MESSAGE dnsParsedMsg;
|
||
PDNS_MESSAGE_BUFFER pDnsBuffer = NULL;
|
||
PDNS_MSG_BUF pDnsMsgBuf = NULL;
|
||
PDNS_RECORD pQueryResultsSet = NULL;
|
||
WORD wMessageLength;
|
||
DWORD dwFlags, dwQueryOptions;
|
||
DNS_CHARSET CharSet;
|
||
BOOL fQ4DefaultSuffix = FALSE;
|
||
|
||
ZeroMemory(&dnsParsedMsg, sizeof(DNS_PARSED_MESSAGE));
|
||
|
||
pDnsBuffer = (PDNS_MESSAGE_BUFFER) Headerp;
|
||
wMessageLength = (WORD) Bufferp->BytesTransferred;
|
||
dwFlags = DNS_PARSE_FLAG_ONLY_QUESTION;
|
||
CharSet = DnsCharSetUtf8;
|
||
|
||
//
|
||
// Dns* functions require byte flipping
|
||
//
|
||
DNS_BYTE_FLIP_HEADER_COUNTS(&pDnsBuffer->MessageHead);
|
||
|
||
dnsStatus = Dns_ParseMessage(
|
||
&dnsParsedMsg,
|
||
pDnsBuffer,
|
||
wMessageLength,
|
||
dwFlags,
|
||
CharSet
|
||
);
|
||
|
||
if (NO_ERROR == dnsStatus)
|
||
{
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: Dns_ParseMessage succeeded!!"
|
||
);
|
||
|
||
//
|
||
// Make a note of whether this question was for our private
|
||
// default domain (ie mshome.net)
|
||
//
|
||
{
|
||
//
|
||
// the question name is in UTF_8 form
|
||
//
|
||
|
||
PWCHAR pszQName = NULL;
|
||
DWORD dwUtf8Size = 0,
|
||
dwSize;
|
||
|
||
dwUtf8Size = strlen((char *)dnsParsedMsg.pQuestionName);
|
||
|
||
dwSize = DnsGetBufferLengthForStringCopy(
|
||
(char *)dnsParsedMsg.pQuestionName,
|
||
dwUtf8Size,
|
||
DnsCharSetUtf8,
|
||
DnsCharSetUnicode
|
||
);
|
||
if (!dwSize)
|
||
{
|
||
//
|
||
// invalid input string
|
||
//
|
||
DWORD dwRet = GetLastError();
|
||
|
||
lpMsgBuf = NULL;
|
||
|
||
FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
NULL,
|
||
dwRet,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &lpMsgBuf,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: DnsGetBufferLengthForStringCopy"
|
||
" returned (0x%08x) %S",
|
||
dwRet,
|
||
lpMsgBuf
|
||
);
|
||
|
||
if (lpMsgBuf) LocalFree(lpMsgBuf);
|
||
}
|
||
else
|
||
{
|
||
pszQName = reinterpret_cast<PWCHAR>(NH_ALLOCATE(dwSize));
|
||
|
||
if (!pszQName)
|
||
{
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: allocation "
|
||
"failed for pszQName"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
ZeroMemory(pszQName, dwSize);
|
||
|
||
DnsUtf8ToUnicode(
|
||
(char *)dnsParsedMsg.pQuestionName,
|
||
dwUtf8Size,
|
||
pszQName,
|
||
dwSize
|
||
);
|
||
|
||
fQ4DefaultSuffix = IsSuffixValid(
|
||
pszQName,
|
||
DNS_HOMENET_SUFFIX
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: %S (%s)",
|
||
pszQName,
|
||
(fQ4DefaultSuffix?"TRUE":"FALSE")
|
||
);
|
||
|
||
NH_FREE(pszQName);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Query
|
||
//
|
||
dwQueryOptions = (
|
||
DNS_QUERY_STANDARD |
|
||
DNS_QUERY_CACHE_ONLY |
|
||
DNS_QUERY_TREAT_AS_FQDN |
|
||
//DNS_QUERY_ALLOW_EMPTY_AUTH_RESP |
|
||
0
|
||
);
|
||
|
||
dnsStatus = DnsQuery_UTF8(
|
||
(LPSTR) dnsParsedMsg.pQuestionName,
|
||
dnsParsedMsg.QuestionType,
|
||
dwQueryOptions,
|
||
NULL,
|
||
&pQueryResultsSet,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
if (dnsStatus)
|
||
{
|
||
lpMsgBuf = NULL;
|
||
|
||
FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
NULL,
|
||
dnsStatus,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &lpMsgBuf,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: (0x%08x) %S",
|
||
dnsStatus,
|
||
lpMsgBuf
|
||
);
|
||
|
||
if (lpMsgBuf) LocalFree(lpMsgBuf);
|
||
}
|
||
|
||
if ((NO_ERROR == dnsStatus) &&
|
||
(pQueryResultsSet) // ??? what do i check to see if
|
||
// there was actually something useful
|
||
// returned from the cache
|
||
)
|
||
{
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: results found in the local DNS Resolver Cache"
|
||
);
|
||
|
||
//
|
||
// Pack & Send back answer; return
|
||
//
|
||
|
||
// set response bit
|
||
dnsParsedMsg.Header.IsResponse = 1;
|
||
|
||
// set the section field of every DNS_RECORD given to us
|
||
// *** NEED TO CHANGE THIS LATER ***
|
||
PDNS_RECORD pRR = pQueryResultsSet;
|
||
DWORD cnt = 0;
|
||
while (pRR)
|
||
{
|
||
pRR->Flags.S.Section = 1;
|
||
cnt++;
|
||
pRR = pRR->pNext;
|
||
}
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: %d records",
|
||
cnt
|
||
);
|
||
|
||
// set global EDNS OPT field to 0 every time
|
||
// *** NEED TO CHANGE THIS LATER ***
|
||
//G_UseEdns = 0;
|
||
|
||
pDnsMsgBuf = Dns_BuildPacket(
|
||
&dnsParsedMsg.Header, // ??? parsed message header should be OK
|
||
TRUE, // ??? no header count copy - counts done automatically?
|
||
dnsParsedMsg.pQuestionName,
|
||
dnsParsedMsg.QuestionType,
|
||
pQueryResultsSet,
|
||
dwQueryOptions,
|
||
TRUE // set to update because of G_UseEdns workaround
|
||
);
|
||
|
||
if (NULL == pDnsMsgBuf)
|
||
{
|
||
lpMsgBuf = NULL;
|
||
|
||
FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
NULL,
|
||
GetLastError(),
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &lpMsgBuf,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: Dns_BuildPacket failed (%S)",
|
||
lpMsgBuf
|
||
);
|
||
|
||
if (lpMsgBuf) LocalFree(lpMsgBuf);
|
||
}
|
||
else
|
||
{
|
||
DWORD dwDnsPktSize = (DWORD)(sizeof(DNS_HEADER) +
|
||
((PCHAR)pDnsMsgBuf->pCurrent -
|
||
(PCHAR)pDnsMsgBuf->MessageBody));
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: Dns_BuildPacket returned pkt of size %d (%d) bytes",
|
||
dwDnsPktSize,
|
||
DNS_MESSAGE_OFFSET(pDnsMsgBuf, pDnsMsgBuf->pCurrent)
|
||
);
|
||
|
||
//
|
||
// send back the answer retrieved from the cache
|
||
//
|
||
PNH_BUFFER NewBufferp = NhAcquireVariableLengthBuffer(
|
||
dwDnsPktSize
|
||
);
|
||
|
||
if (!NewBufferp)
|
||
{
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: could not acquire buffer"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Dns* functions return in host order ???
|
||
//
|
||
DNS_BYTE_FLIP_HEADER_COUNTS(&pDnsMsgBuf->MessageHead);
|
||
|
||
//
|
||
// Reference the interface now since we are replying
|
||
// to the query
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep))
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
Referenced = FALSE;
|
||
}
|
||
else
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
|
||
memcpy(
|
||
NewBufferp->Buffer,
|
||
&pDnsMsgBuf->MessageHead,
|
||
dwDnsPktSize
|
||
);
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DnsComponentReference,
|
||
Bufferp->Socket,
|
||
Bufferp->ReadAddress.sin_addr.s_addr,
|
||
Bufferp->ReadAddress.sin_port,
|
||
NewBufferp,
|
||
dwDnsPktSize,
|
||
DnsWriteCompletionRoutine,
|
||
Interfacep,
|
||
NULL
|
||
);
|
||
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
if (!Error)
|
||
{
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.ResponsesSent)
|
||
);
|
||
}
|
||
else
|
||
{
|
||
NhReleaseBuffer(NewBufferp);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_RESPONSE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Socket)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
LocalFree(pDnsMsgBuf);
|
||
|
||
}
|
||
|
||
//
|
||
// CLEANUP
|
||
//
|
||
|
||
DnsRecordListFree(
|
||
pQueryResultsSet,
|
||
DnsFreeRecordListDeep
|
||
);
|
||
|
||
// buffer is reposted below
|
||
|
||
}
|
||
else
|
||
if (//(DNS_ERROR_RECORD_DOES_NOT_EXIST == dnsStatus) &&
|
||
(fQ4DefaultSuffix))
|
||
{
|
||
//
|
||
// this was a question for our default suffix
|
||
// we send a name error reply back to the client
|
||
// - note however that we dont publish an SOA
|
||
// record for our default suffix domain
|
||
//
|
||
|
||
//
|
||
// Undoing Flip above
|
||
//
|
||
DNS_BYTE_FLIP_HEADER_COUNTS(&pDnsBuffer->MessageHead);
|
||
|
||
DWORD dwDnsPktSize = Bufferp->BytesTransferred;
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: returning error message"
|
||
);
|
||
|
||
//
|
||
// send back the negative answer
|
||
//
|
||
PNH_BUFFER NewBufferp = NhAcquireVariableLengthBuffer(
|
||
dwDnsPktSize
|
||
);
|
||
|
||
if (!NewBufferp)
|
||
{
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: could not acquire buffer"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Reference the interface now since we are replying
|
||
// to the query
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep))
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
Referenced = FALSE;
|
||
}
|
||
else
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
|
||
memcpy(
|
||
NewBufferp->Buffer,
|
||
Bufferp->Buffer,
|
||
dwDnsPktSize
|
||
);
|
||
|
||
PDNS_HEADER NewHeaderp = (PDNS_HEADER)NewBufferp->Buffer;
|
||
|
||
//
|
||
// set response bit
|
||
//
|
||
NewHeaderp->IsResponse = 1;
|
||
|
||
//
|
||
// set "Name does not exist" error in the RCode field
|
||
//
|
||
NewHeaderp->ResponseCode = DNS_RCODE_NXDOMAIN;
|
||
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DnsComponentReference,
|
||
Bufferp->Socket,
|
||
Bufferp->ReadAddress.sin_addr.s_addr,
|
||
Bufferp->ReadAddress.sin_port,
|
||
NewBufferp,
|
||
dwDnsPktSize,
|
||
DnsWriteCompletionRoutine,
|
||
Interfacep,
|
||
NULL
|
||
);
|
||
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
if (!Error)
|
||
{
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.ResponsesSent)
|
||
);
|
||
}
|
||
else
|
||
{
|
||
NhReleaseBuffer(NewBufferp);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_RESPONSE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Socket)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// buffer is reposted below
|
||
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Undoing Flip above
|
||
//
|
||
DNS_BYTE_FLIP_HEADER_COUNTS(&pDnsBuffer->MessageHead);
|
||
|
||
//
|
||
// Reference the interface now in case we need to forward the query
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (DNS_REFERENCE_INTERFACE(Interfacep))
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
}
|
||
else
|
||
{
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
Referenced = FALSE;
|
||
}
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
|
||
//
|
||
// See if this query is already pending;
|
||
// if not, create a record for it on the receiving interface.
|
||
//
|
||
|
||
if (DnsIsPendingQuery(Interfacep, Bufferp))
|
||
{
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: query already pending"
|
||
);
|
||
|
||
if (Referenced)
|
||
{
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
}
|
||
}
|
||
else
|
||
if (!Referenced ||
|
||
!(Queryp = DnsRecordQuery(Interfacep, Bufferp)))
|
||
{
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
NhTrace(
|
||
TRACE_FLAG_DNS,
|
||
"DnsProcessQueryMessage: query could not be created"
|
||
);
|
||
|
||
if (Referenced)
|
||
{
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Write the new ID in the query
|
||
//
|
||
|
||
Headerp->Xid = Queryp->QueryId;
|
||
|
||
//
|
||
// Send the query to our servers
|
||
//
|
||
|
||
Error =
|
||
DnsSendQuery(
|
||
Interfacep,
|
||
Queryp,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// This buffer is now associated with an outstanding query,
|
||
// so don't repost it below.
|
||
//
|
||
|
||
if (!Error)
|
||
{
|
||
Bufferp = NULL;
|
||
RELEASE_LOCK(Interfacep);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Delete the query, but not the buffer, which we repost below
|
||
//
|
||
Queryp->Bufferp = NULL;
|
||
DnsDeleteQuery(Interfacep, Queryp);
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// cleanup question name
|
||
//
|
||
LocalFree(dnsParsedMsg.pQuestionName); // ??? is LocalFree OK?
|
||
}
|
||
|
||
//
|
||
// Post another read
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
} else {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
do {
|
||
Error =
|
||
NhReadDatagramSocket(
|
||
&DnsComponentReference,
|
||
Socket,
|
||
Bufferp,
|
||
DnsReadCompletionRoutine,
|
||
Context,
|
||
Context2
|
||
);
|
||
//
|
||
// A connection-reset error indicates that our last *send*
|
||
// could not be delivered at its destination.
|
||
// We could hardly care less; so issue the read again,
|
||
// immediately.
|
||
//
|
||
} while (Error == WSAECONNRESET);
|
||
if (Error) {
|
||
ACQUIRE_LOCK(Interfacep);
|
||
DnsDeferReadInterface(Interfacep, Socket);
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhErrorLog(
|
||
IP_DNS_PROXY_LOG_RECEIVE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Socket)
|
||
);
|
||
if (Bufferp) { NhReleaseBuffer(Bufferp); }
|
||
}
|
||
}
|
||
|
||
} // DnsProcessQueryMessage
|
||
|
||
|
||
VOID
|
||
DnsProcessResponseMessage(
|
||
PDNS_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to process a DNS response message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the query was received
|
||
|
||
Bufferp - the buffer containing the query
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked internally in the context of a worker-thread completion routine,
|
||
with an outstanding reference to 'Interfacep' from the time the
|
||
read-operation was begun.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Context;
|
||
PVOID Context2;
|
||
ULONG Error;
|
||
PDNS_HEADER Headerp;
|
||
PDNS_QUERY Queryp;
|
||
SOCKET Socket;
|
||
|
||
PROFILE("DnsProcessResponseMessage");
|
||
|
||
#if DBG
|
||
NhDump(
|
||
TRACE_FLAG_DNS,
|
||
Bufferp->Buffer,
|
||
Bufferp->BytesTransferred,
|
||
1
|
||
);
|
||
#endif
|
||
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.ResponsesReceived)
|
||
);
|
||
|
||
Headerp = (PDNS_HEADER)Bufferp->Buffer;
|
||
|
||
Socket = Bufferp->Socket;
|
||
Context = Bufferp->Context;
|
||
Context2 = Bufferp->Context2;
|
||
|
||
//
|
||
// Reference the interface and attempt to forward the response
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
} else {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
|
||
ACQUIRE_LOCK(Interfacep);
|
||
|
||
//
|
||
// See if the response is for a pending query
|
||
//
|
||
|
||
if (!(Queryp = DnsMapResponseToQuery(Interfacep, Headerp->Xid))) {
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.MessagesIgnored)
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// We have the corresponding query.
|
||
// Send the response back to the client.
|
||
//
|
||
|
||
Headerp->Xid = Queryp->SourceId;
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DnsComponentReference,
|
||
Bufferp->Socket,
|
||
Queryp->SourceAddress,
|
||
Queryp->SourcePort,
|
||
Bufferp,
|
||
Bufferp->BytesTransferred,
|
||
DnsWriteCompletionRoutine,
|
||
Interfacep,
|
||
(PVOID)Queryp->QueryId
|
||
);
|
||
|
||
RELEASE_LOCK(Interfacep);
|
||
|
||
//
|
||
// This buffer is in use for a send-operation,
|
||
// so don't repost it below.
|
||
//
|
||
|
||
if (!Error) {
|
||
Bufferp = NULL;
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DnsStatistics.ResponsesSent)
|
||
);
|
||
} else {
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhWarningLog(
|
||
IP_DNS_PROXY_LOG_RESPONSE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Socket)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Post another read buffer
|
||
//
|
||
|
||
EnterCriticalSection(&DnsInterfaceLock);
|
||
if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
if (Bufferp) { NhReleaseBuffer(Bufferp); }
|
||
} else {
|
||
LeaveCriticalSection(&DnsInterfaceLock);
|
||
do {
|
||
Error =
|
||
NhReadDatagramSocket(
|
||
&DnsComponentReference,
|
||
Socket,
|
||
Bufferp,
|
||
DnsReadCompletionRoutine,
|
||
Context,
|
||
Context2
|
||
);
|
||
//
|
||
// A connection-reset error indicates that our last *send*
|
||
// could not be delivered at its destination.
|
||
// We could hardly care less; so issue the read again,
|
||
// immediately.
|
||
//
|
||
} while (Error == WSAECONNRESET);
|
||
if (Error) {
|
||
ACQUIRE_LOCK(Interfacep);
|
||
DnsDeferReadInterface(Interfacep, Socket);
|
||
RELEASE_LOCK(Interfacep);
|
||
DNS_DEREFERENCE_INTERFACE(Interfacep);
|
||
if (Bufferp) { NhReleaseBuffer(Bufferp); }
|
||
NhErrorLog(
|
||
IP_DNS_PROXY_LOG_RECEIVE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
} // DnsProcessResponseMessage
|
||
|
||
|