mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
914 lines
27 KiB
914 lines
27 KiB
/*++
|
|
|
|
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
|
|
|
|
|