windows-nt/Source/XPSP1/NT/ds/dns/dnslib/print.c

5422 lines
115 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
print.c
Abstract:
Domain Name System (DNS) Library
Print routines.
Author:
Jim Gilroy (jamesg) February 8, 1997
Revision History:
--*/
#include "local.h"
#include "svcguid.h" // RnR guids
#include "..\dnsapi\dnsapip.h" // Private query stuff
#include "..\resolver\idl\resrpc.h" // Resolver interface structs
//
// Print globals
//
CRITICAL_SECTION DnsAtomicPrintCs;
PCRITICAL_SECTION pDnsAtomicPrintCs = NULL;
//
// Empty string for simple switching of UTF-8/Unicode print
// (macros in dnslib.h)
//
DWORD DnsEmptyString = 0;
//
// Indenting
//
// Serve up as many indenting tabs as indent level indicates
//
CHAR IndentString[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
#define INDENT_STRING( level ) (IndentString + (sizeof(IndentString) - 1 - (level)))
//
// Print Locking
//
// Unless caller initilizes print locking by supplying lock,
// print locking is disabled.
//
VOID
DnsPrint_InitLocking(
IN PCRITICAL_SECTION pLock
)
/*++
Routine Description:
Setup DNS printing to use a lock.
Can use already initialized lock from caller, or will
create default lock.
Arguments:
pLock - ptr to CS to use as lock; if NULL, create one
Return Value:
None
--*/
{
if ( pLock )
{
pDnsAtomicPrintCs = pLock;
}
else if ( !pDnsAtomicPrintCs )
{
InitializeCriticalSection( &DnsAtomicPrintCs );
pDnsAtomicPrintCs = &DnsAtomicPrintCs;
}
}
VOID
DnsPrint_Lock(
VOID
)
/*++
Routine Description:
Lock to get atomic DNS print.
--*/
{
if ( pDnsAtomicPrintCs )
{
EnterCriticalSection( pDnsAtomicPrintCs );
}
}
VOID
DnsPrint_Unlock(
VOID
)
/*++
Routine Description:
Unlock to debug print.
--*/
{
if ( pDnsAtomicPrintCs )
{
LeaveCriticalSection( pDnsAtomicPrintCs );
}
}
//
// Print routines for general types and structures
//
VOID
DnsPrint_String(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader OPTIONAL,
IN PSTR pszString,
IN BOOL fUnicode,
IN PSTR pszTrailer OPTIONAL
)
/*++
Routine Description:
Print DNS string given in either Unicode or UTF-8 format.
--*/
{
if ( !pszHeader )
{
pszHeader = "";
}
if ( !pszTrailer )
{
pszTrailer = "";
}
if ( ! pszString )
{
PrintRoutine(
pContext,
"%s(NULL DNS string ptr)%s",
pszHeader,
pszTrailer );
}
else if (fUnicode)
{
PrintRoutine(
pContext,
"%s%S%s",
pszHeader,
(PWSTR ) pszString,
pszTrailer );
}
else
{
PrintRoutine(
pContext,
"%s%s%s",
pszHeader,
(PSTR ) pszString,
pszTrailer );
}
}
VOID
DnsPrint_StringCharSet(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader OPTIONAL,
IN PSTR pszString,
IN DNS_CHARSET CharSet,
IN PSTR pszTrailer OPTIONAL
)
/*++
Routine Description:
Print string of given CHARSET.
--*/
{
DnsPrint_String(
PrintRoutine,
pContext,
pszHeader,
pszString,
(CharSet == DnsCharSetUnicode),
pszTrailer );
}
VOID
DnsPrint_UnicodeStringBytes(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PWCHAR pUnicode,
IN DWORD Length
)
/*++
Routine Description:
Print chars (WORDs) of unicode string.
--*/
{
DWORD i;
PrintRoutine(
pContext,
"%s\r\n"
"\twide string %S\r\n"
"\tlength %d\r\n"
"\tbytes ",
pszHeader,
pUnicode,
Length );
for ( i=0; i<Length; i++ )
{
PrintRoutine(
pContext,
"%04hx ",
pUnicode[i] );
}
printf( "\r\n" );
}
VOID
DnsPrint_Utf8StringBytes(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PCHAR pUtf8,
IN DWORD Length
)
/*++
Routine Description:
Print bytes of UTF8 string.
--*/
{
DWORD i;
PrintRoutine(
pContext,
"%s\r\n"
"\tUTF8 string %s\r\n"
"\tlength %d\r\n"
"\tbytes ",
pszHeader,
pUtf8,
Length );
for ( i=0; i<Length; i++ )
{
PrintRoutine(
pContext,
"%02x ",
(UCHAR) pUtf8[i] );
}
printf( "\r\n" );
}
VOID
DnsPrint_StringArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR * StringArray,
IN DWORD Count, OPTIONAL
IN BOOL fUnicode
)
/*++
Routine Description:
Print string array.
--*/
{
DWORD i = 0;
PCHAR pstr;
if ( !pszHeader )
{
pszHeader = "StringArray:";
}
if ( !StringArray )
{
PrintRoutine(
pContext,
"%s NULL pointer!\r\n",
pszHeader );
}
DnsPrint_Lock();
if ( Count )
{
PrintRoutine(
pContext,
"%s Count = %d\r\n",
pszHeader,
Count );
}
else
{
PrintRoutine(
pContext,
"%s\r\n",
pszHeader );
}
//
// print args
// - stop at Count (if given)
// OR
// - on NULL arg (if no count given)
//
while ( (!Count || i < Count) )
{
pstr = StringArray[i++];
if ( !pstr && !Count )
{
break;
}
PrintRoutine(
pContext,
(fUnicode) ? "\t%S\r\n" : "\t%s\r\n",
pstr );
}
DnsPrint_Unlock();
}
VOID
DnsPrint_Argv(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN CHAR ** Argv,
IN DWORD Argc, OPTIONAL
IN BOOL fUnicode
)
/*++
Routine Description:
Print Argv array.
--*/
{
//
// this is just special case of string print
//
DnsPrint_StringArray(
PrintRoutine,
pContext,
pszHeader
? pszHeader
: "Argv:",
Argv,
Argc,
fUnicode );
}
VOID
DnsPrint_DwordArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR pszName,
IN DWORD dwCount,
IN PDWORD adwArray
)
/*++
Routine Description:
Print DWORD array.
--*/
{
DWORD i;
DnsPrint_Lock();
if ( pszHeader )
{
PrintRoutine(
pContext,
pszHeader );
}
if ( !pszName )
{
pszName = "DWORD";
}
PrintRoutine(
pContext,
"%s Array Count = %d\r\n",
pszName,
dwCount );
for( i=0; i<dwCount; i++ )
{
PrintRoutine(
pContext,
"\t%s[%d] => 0x%p (%d)\r\n",
pszName,
i,
adwArray[i],
adwArray[i] );
}
DnsPrint_Unlock();
}
VOID
DnsPrint_IpAddressArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR pszName,
IN DWORD dwIpAddrCount,
IN PIP_ADDRESS pIpAddrs
)
/*++
Routine Description:
Print IP address array.
--*/
{
DWORD i;
DnsPrint_Lock();
if ( !pszName )
{
pszName = "IP Addr";
}
PrintRoutine(
pContext,
"%s%s Count = %d\r\n",
pszHeader ? pszHeader : "",
pszName,
dwIpAddrCount );
if ( dwIpAddrCount != 0 && pIpAddrs != NULL )
{
// print array with count
// use character print so works even if NOT DWORD aligned
for( i=0; i<dwIpAddrCount; i++ )
{
PrintRoutine(
pContext,
"\t%s[%d] => %d.%d.%d.%d\r\n",
pszName,
i,
* ( (PUCHAR) &pIpAddrs[i] + 0 ),
* ( (PUCHAR) &pIpAddrs[i] + 1 ),
* ( (PUCHAR) &pIpAddrs[i] + 2 ),
* ( (PUCHAR) &pIpAddrs[i] + 3 ) );
}
}
#if 0
// this spins if printing zero length IP_ARRAY struct
else if ( pIpAddrs != NULL )
{
// print NULL terminated array (ex. hostents IPs)
i = 0;
while ( pIpAddrs[i] )
{
PrintRoutine(
pContext,
"\t%s[%d] => %s\r\n",
pszName,
i,
inet_ntoa( *(struct in_addr *) &pIpAddrs[i] ) );
}
}
#endif
DnsPrint_Unlock();
}
VOID
DnsPrint_IpArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR pszName,
IN PIP_ARRAY pIpArray
)
/*++
Routine Description:
Print IP address array struct
Just pass through to more generic print routine.
--*/
{
// protect against NULL case
if ( !pIpArray )
{
PrintRoutine(
pContext,
"%s\tNULL IP Array.\r\n",
pszHeader ? pszHeader : "" );
}
// call uncoupled IP array routine
else
{
DnsPrint_IpAddressArray(
PrintRoutine,
pContext,
pszHeader,
pszName,
pIpArray->AddrCount,
pIpArray->AddrArray );
}
}
VOID
DnsPrint_DnsAddrArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_ADDR_ARRAY pAddrArray
)
/*++
Routine Description:
Print IP address info array.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Addr Array";
}
if ( !pAddrArray )
{
PrintRoutine(
pContext,
"%s NULL AddrArray ptr.\r\n",
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
" Ptr = %p\r\n"
" Count = %d\r\n",
pszHeader ? pszHeader : "IP Address Info",
pAddrArray,
pAddrArray->AddrCount );
//
// print array up to count
//
// DCR: IP6 address info blob
//
for( i=0; i<pAddrArray->AddrCount; i++ )
{
IP_ADDRESS ip = pAddrArray->AddrArray[i].IpAddr;
IP_ADDRESS subnetMask = pAddrArray->AddrArray[i].SubnetMask;
PrintRoutine(
pContext,
"\tIP Address[%d] => %d.%d.%d.%d\r\n"
"\tSubnetMask[%d] => %d.%d.%d.%d\r\n",
i,
(ip & 0xff),
((ip>>8) & 0xff),
((ip>>16) & 0xff),
((ip>>24) & 0xff),
i,
(subnetMask & 0xff),
((subnetMask>>8) & 0xff),
((subnetMask>>16) & 0xff),
((subnetMask>>24) & 0xff)
);
}
DnsPrint_Unlock();
}
VOID
DnsPrint_Ip6Address(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PIP6_ADDRESS pIp6Address,
IN PSTR pszTrailer
)
/*++
Routine Description:
Print IP6 address.
Arguments:
PrintRoutine -- print routine to call
pContext -- first argument to print routine
pszHeader -- header to print
NOTE: unlike other print routines this routine
requires header to contain newline,tab, etc if
multiline print is desired; the reason is to allow
use of this routine for single line print
pIp6Address -- ptr to IP6 address to print
pszTrailer -- trailer to print
NOTE: again this routine is designed to allow single
line print; if newline required after print, send
newline in trailer
Return Value:
Ptr to next location in buffer (the terminating NULL).
--*/
{
CHAR buffer[ IP6_ADDRESS_STRING_BUFFER_LENGTH ];
if ( !pszHeader )
{
pszHeader = "IP6 Address: ";
}
if ( !pszTrailer )
{
pszHeader = "\r\n";
}
if ( !pIp6Address )
{
PrintRoutine(
pContext,
"%s NULL IP6 address ptr.%s",
pszHeader,
pszTrailer );
}
// convert IP6 address to string
Dns_Ip6AddressToString_A(
buffer,
pIp6Address );
PrintRoutine(
pContext,
"%s%s%s",
pszHeader,
buffer,
pszTrailer );
}
//
// Print routines for DNS types and structures
//
INT
Dns_WritePacketNameToBuffer(
OUT PCHAR pBuffer,
OUT PCHAR * ppBufferOut,
IN PBYTE pMsgName,
IN PDNS_HEADER pMsgHead, OPTIONAL
IN PBYTE pMsgEnd OPTIONAL
)
/*++
Routine Description:
Write packet name into buffer.
Arguments:
pBuffer - buffer to print to,
bounds checking done only on each loop to limit to
twice DNS_MAX_NAME_LENGTH, recommend input buffer
of at least that length
ppBufferOut - ptr to terminating NULL in buffer conversion, this
is position at which additional printing to buffer
could resume
pMsgName - ptr to name in packet to print
pMsgHead - ptr to DNS message; need for offsetting, if not given
names are not printed past first offset
pMsgEnd - ptr to end of message, specifically byte immediately after
message
Return Value:
Count of bytes in packet name occupied.
This offset from pMsgName is the next field in the packet.
Zero return indicates error in message name.
--*/
{
register PUCHAR pchbuf;
register PUCHAR pchmsg;
register UCHAR cch;
PCHAR pbufStop;
PCHAR pnextLabel;
UCHAR compressionType;
WORD offset;
PCHAR pbyteAfterFirstOffset = NULL;
//
// no message end specified?
// make it max ptr so we can do single test for ptr validity
// rather than testing for pMsgEnd existence first
//
if ( !pMsgEnd )
{
pMsgEnd = (PVOID)(INT_PTR)(-1);
}
//
// loop until copy as printable name, or hit compression or name error
//
pchbuf = pBuffer;
pbufStop = pchbuf + DNS_MAX_NAME_LENGTH + DNS_MAX_LABEL_LENGTH;
pchmsg = pMsgName;
while ( 1 )
{
// bounds checking to survive bad packet
//
// DEVNOTE: note this is not strictly a bad packet (could be just a
// heck of a lot of labels) and we could
// a) let packet processing proceed without printing
// or
// b) require buffer that could contain max legal DNS name
// but not worth the effort
if ( pchbuf >= pbufStop )
{
pchbuf += sprintf(
pchbuf,
"[ERROR name exceeds safe print buffer length]\r\n" );
pchmsg = pMsgName;
break;
}
cch = (UCHAR) *pchmsg++;
compressionType = cch & 0xC0;
DNSDBG( OFF, (
"byte = (%d) (0x%02x)\r\n"
"compress flag = (%d) (0x%02x)\r\n",
cch, cch,
compressionType, compressionType ));
//
// normal length byte
// - write length field
// - copy label to print buffer
//
if ( compressionType == 0 )
{
pchbuf += sprintf( pchbuf, "(%d)", (INT)cch );
// terminate at root name
if ( ! cch )
{
break;
}
// check that within packet
pnextLabel = pchmsg + cch;
if ( pnextLabel >= pMsgEnd )
{
pchbuf += sprintf(
pchbuf,
"[ERROR length byte: 0x%02X at %p leads outside message]\r\n",
cch,
pchmsg );
// force zero byte return
pchmsg = pMsgName;
break;
}
// copy label to output string
memcpy(
pchbuf,
pchmsg,
cch );
pchbuf += cch;
pchmsg = pnextLabel;
continue;
}
//
// valid compression
//
else if ( compressionType == (UCHAR)0xC0 )
{
// check that compression word not straddling message end
if ( pchmsg >= pMsgEnd )
{
pchbuf += sprintf(
pchbuf,
"[ERROR compression word at %p is outside message]\r\n",
pchmsg );
// force zero byte return
pchmsg = pMsgName;
break;
}
// calculate offset
offset = cch; // high byte
offset <<= 8;
offset |= *pchmsg++; // low byte
pchbuf += sprintf(
pchbuf,
"[%04hX]",
offset );
if ( pMsgHead )
{
//
// on first compression, save ptr to byte immediately after
// name, so can calculate next byte
//
// save ptr to next byte in mess, to calculate actual length
// name takes up in packet
//
if ( ! pbyteAfterFirstOffset )
{
pbyteAfterFirstOffset = pchmsg;
}
//
// jump to offset for continuation of name
// - clear two highest bits to get length
//
offset = offset ^ 0xC000;
DNS_ASSERT( (offset & 0xC000) == 0 );
pnextLabel = (PCHAR)pMsgHead + offset;
if ( pnextLabel >= pchmsg - sizeof(WORD) )
{
pchbuf += sprintf(
pchbuf,
"[ERROR offset at %p to higher byte in packet %p]\r\n",
pchmsg - sizeof(WORD),
pnextLabel );
break;
}
pchmsg = pnextLabel;
continue;
}
// if no ptr to message head, can not continue at offset
// NULL terminate previous label
else
{
*pchbuf++ = 0;
break;
}
}
//
// invalid compression
// - force zero byte return to indicate error
else
{
pchbuf += sprintf(
pchbuf,
"[ERROR length byte: 0x%02X]",
cch );
pchmsg = pMsgName;
break;
}
}
//
// return ptr to next position in output buffer
//
if ( ppBufferOut )
{
*ppBufferOut = pchbuf;
}
//
// return number of bytes read from message
//
if ( pbyteAfterFirstOffset )
{
pchmsg = pbyteAfterFirstOffset;
}
return (INT)( pchmsg - pMsgName );
}
INT
DnsPrint_PacketName(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader, OPTIONAL
IN PBYTE pMsgName,
IN PDNS_HEADER pMsgHead, OPTIONAL
IN PBYTE pMsgEnd, OPTIONAL
IN PSTR pszTrailer OPTIONAL
)
/*++
Routine Description:
Print DNS name given in packet format.
Arguments:
PrintRoutine - routine to print with
pszHeader - header to print
pMsgHead - ptr to DNS message; need for offsetting, if not given
names are not printed past first offset
pMsgName - ptr to name in packet to print
pMsgEnd - ptr to end of message; OPTIONAL, but needed to protect
against AV accessing bad packet names
pszTrailer - trailer to print after name
Return Value:
Count of bytes in packet name occupied.
This offset from pMsgName is the next field in the packet.
Zero return indicates error in message name.
--*/
{
INT countNameBytes;
// name buffer, allow space for full name, plus parens on length
// fields plus several compression flags
CHAR PrintName[ 2*DNS_MAX_NAME_LENGTH ];
if ( ! pMsgName )
{
PrintRoutine(
pContext,
"%s(NULL packet name ptr)%s\r\n",
pszHeader ? pszHeader : "",
pszTrailer ? pszTrailer : ""
);
return 0;
}
//
// build packet name into buffer, then print
//
countNameBytes = Dns_WritePacketNameToBuffer(
PrintName,
NULL,
pMsgName,
pMsgHead,
pMsgEnd
);
PrintRoutine(
pContext,
"%s%s%s",
pszHeader ? pszHeader : "",
PrintName,
pszTrailer ? pszTrailer : ""
);
return( countNameBytes );
}
VOID
DnsPrint_Message(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_MSG_BUF pMsg
)
/*++
Routine Description:
Print DNS message buffer.
Includes context information as well as actual DNS message.
--*/
{
PDNS_HEADER pmsgHeader;
PCHAR pchRecord;
PBYTE pmsgEnd;
INT i;
INT isection;
INT cchName;
WORD wLength;
WORD wOffset;
WORD wXid;
WORD wQuestionCount;
WORD wAnswerCount;
WORD wNameServerCount;
WORD wAdditionalCount;
WORD countSectionRR;
BOOL fFlipped = FALSE;
DnsPrint_Lock();
if ( pszHeader )
{
PrintRoutine(
pContext,
"%s\r\n",
pszHeader );
}
// get message info
//
// note: length may not be correctly set while building message,
// so make pmsgEnd greater of given length and pCurrent ptr
// but allow for case where set back to pre-OPT length
//
wLength = pMsg->MessageLength;
pmsgHeader = &pMsg->MessageHead;
pmsgEnd = ((PBYTE)pmsgHeader) + wLength;
if ( pmsgEnd < pMsg->pCurrent &&
pmsgEnd != pMsg->pPreOptEnd )
{
pmsgEnd = pMsg->pCurrent;
}
//
// print header info
//
PrintRoutine(
pContext,
"%s %s info at %p\r\n"
" Socket = %d\r\n"
" Remote addr %s, port %ld\r\n"
" Buf length = 0x%04x\r\n"
" Msg length = 0x%04x\r\n"
" Message:\r\n",
( pMsg->fTcp
? "TCP"
: "UDP" ),
( pmsgHeader->IsResponse
? "response"
: "question" ),
pMsg,
pMsg->Socket,
MSG_REMOTE_IP_STRING( pMsg ),
MSG_REMOTE_IP_PORT( pMsg ),
pMsg->BufferLength,
wLength
);
PrintRoutine(
pContext,
" XID 0x%04hx\r\n"
" Flags 0x%04hx\r\n"
" QR 0x%lx (%s)\r\n"
" OPCODE 0x%lx (%s)\r\n"
" AA 0x%lx\r\n"
" TC 0x%lx\r\n"
" RD 0x%lx\r\n"
" RA 0x%lx\r\n"
" Z 0x%lx\r\n"
" RCODE 0x%lx (%s)\r\n"
" QCOUNT 0x%hx\r\n"
" ACOUNT 0x%hx\r\n"
" NSCOUNT 0x%hx\r\n"
" ARCOUNT 0x%hx\r\n",
pmsgHeader->Xid,
ntohs((*((PWORD)pmsgHeader + 1))),
pmsgHeader->IsResponse,
(pmsgHeader->IsResponse ? "response" : "question"),
pmsgHeader->Opcode,
Dns_OpcodeString( pmsgHeader->Opcode ),
pmsgHeader->Authoritative,
pmsgHeader->Truncation,
pmsgHeader->RecursionDesired,
pmsgHeader->RecursionAvailable,
pmsgHeader->Reserved,
pmsgHeader->ResponseCode,
Dns_ResponseCodeString( pmsgHeader->ResponseCode ),
pmsgHeader->QuestionCount,
pmsgHeader->AnswerCount,
pmsgHeader->NameServerCount,
pmsgHeader->AdditionalCount );
//
// determine if byte flipped and get correct count
//
wXid = pmsgHeader->Xid;
wQuestionCount = pmsgHeader->QuestionCount;
wAnswerCount = pmsgHeader->AnswerCount;
wNameServerCount = pmsgHeader->NameServerCount;
wAdditionalCount = pmsgHeader->AdditionalCount;
if ( wQuestionCount )
{
fFlipped = wQuestionCount & 0xff00;
}
else if ( wNameServerCount )
{
fFlipped = wNameServerCount & 0xff00;
}
if ( fFlipped )
{
wXid = ntohs( wXid );
wQuestionCount = ntohs( wQuestionCount );
wAnswerCount = ntohs( wAnswerCount );
wNameServerCount = ntohs( wNameServerCount );
wAdditionalCount = ntohs( wAdditionalCount );
}
//
// catch record flipping problems -- all are flipped or none at all
// and no record count should be > 256 EXCEPT answer count
// during FAST zone transfer
//
DNS_ASSERT( ! (wQuestionCount & 0xff00) );
DNS_ASSERT( ! (wNameServerCount & 0xff00) );
DNS_ASSERT( ! (wAdditionalCount & 0xff00) );
#if 0
//
// stop here if WINS response -- don't have parsing ready
//
if ( pmsgHeader->IsResponse && IS_WINS_XID(wXid) )
{
PrintRoutine(
pContext,
" WINS Response packet.\r\n\r\n" );
goto Unlock;
}
#endif
//
// print questions and resource records
//
pchRecord = (PCHAR)(pmsgHeader + 1);
for ( isection=0; isection<4; isection++)
{
PrintRoutine(
pContext,
" %s Section:\r\n",
Dns_SectionNameString( isection, pmsgHeader->Opcode ) );
if ( isection==0 )
{
countSectionRR = wQuestionCount;
}
else if ( isection==1 )
{
countSectionRR = wAnswerCount;
}
else if ( isection==2 )
{
countSectionRR = wNameServerCount;
}
else if ( isection==3 )
{
countSectionRR = wAdditionalCount;
}
for ( i=0; i < countSectionRR; i++ )
{
//
// verify not overrunning length
// - check against pCurrent as well as message length
// so can print packets while being built
//
wOffset = (WORD)(pchRecord - (PCHAR)pmsgHeader);
if ( wOffset >= wLength
&&
pchRecord >= pMsg->pCurrent )
{
PrintRoutine(
pContext,
"ERROR: BOGUS PACKET:\r\n"
"\tFollowing RR (offset %d) past packet length (%d).\r\n",
wOffset,
wLength
);
goto Unlock;
}
//
// print RR name
//
PrintRoutine(
pContext,
" Name Offset = 0x%04x\r\n",
wOffset
);
cchName = DnsPrint_PacketName(
PrintRoutine,
pContext,
" Name \"",
pchRecord,
pmsgHeader,
pmsgEnd,
"\"\r\n" );
if ( ! cchName )
{
PrintRoutine(
pContext,
"ERROR: Invalid name length, stop packet print\r\n" );
DNS_ASSERT( FALSE );
break;
}
pchRecord += cchName;
// print question or resource record
if ( isection == 0 )
{
PrintRoutine(
pContext,
" QTYPE %d\r\n"
" QCLASS %d\r\n",
FlipUnalignedWord( pchRecord ),
FlipUnalignedWord( pchRecord + sizeof(WORD) )
);
pchRecord += sizeof( DNS_WIRE_QUESTION );
}
else
{
pchRecord += DnsPrint_PacketRecord(
PrintRoutine,
pContext,
NULL,
(PDNS_WIRE_RECORD) pchRecord,
pmsgHeader,
pmsgEnd
);
}
}
}
// check that at proper end of packet
wOffset = (WORD)(pchRecord - (PCHAR)pmsgHeader);
if ( pchRecord < pMsg->pCurrent || wOffset < wLength )
{
PrintRoutine(
pContext,
"WARNING: message continues beyond these records\r\n"
"\tpch = %p, pCurrent = %p, %d bytes\r\n"
"\toffset = %d, msg length = %d, %d bytes\r\n",
pchRecord,
pMsg->pCurrent,
pMsg->pCurrent - pchRecord,
wOffset,
wLength,
wLength - wOffset );
}
PrintRoutine(
pContext,
" Message length = %04x\n\r\n",
wOffset );
Unlock:
DnsPrint_Unlock();
} // DnsPrint_Message
INT
DnsPrint_PacketRecord(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_WIRE_RECORD pMsgRR,
IN PDNS_HEADER pMsgHead, OPTIONAL
IN PBYTE pMsgEnd OPTIONAL
)
/*++
Routine Description:
Print RR in packet format.
Arguments:
pszHeader - Header message/name for RR.
pMsgRR - resource record to print
pMsgHead - ptr to DNS message; need for offsetting, if not given
names are not printed past first offset
pMsgEnd - ptr to end of message, specifically byte immediately after
message
Return Value:
Number of bytes in record.
--*/
{
PCHAR pdata = (PCHAR)(pMsgRR + 1);
PCHAR pdataStop;
WORD dlen = FlipUnalignedWord( &pMsgRR->DataLength );
WORD type;
PCHAR pRRString;
DnsPrint_Lock();
//
// print RR fixed fields
//
type = FlipUnalignedWord( &pMsgRR->RecordType );
pRRString = Dns_RecordStringForType( type );
if ( pszHeader )
{
PrintRoutine(
pContext,
"%s\r\n",
pszHeader );
}
PrintRoutine(
pContext,
" TYPE %s (%u)\r\n"
" CLASS %u\r\n"
" TTL %lu\r\n"
" DLEN %u\r\n"
" DATA ",
pRRString,
type,
FlipUnalignedWord( &pMsgRR->RecordClass ),
FlipUnalignedDword( &pMsgRR->TimeToLive ),
dlen );
//
// update records may not have data
//
if ( dlen == 0 )
{
PrintRoutine(
pContext,
"(none)\r\n" );
goto Done;
}
// stop byte after RR data
pdataStop = pdata + dlen;
if ( pMsgEnd < pdataStop )
{
PrintRoutine(
pContext,
"ERROR: record at %p extends past end of packet!\n"
"\tpmsg = %p\n"
"\tpmsgEnd = %p\n"
"\trecord end = %p\n",
pMsgRR,
pMsgHead,
pMsgEnd,
pdataStop );
goto Done;
}
//
// print RR data
//
switch ( type )
{
case DNS_TYPE_A:
PrintRoutine(
pContext,
"%d.%d.%d.%d\r\n",
* (PUCHAR)( pdata + 0 ),
* (PUCHAR)( pdata + 1 ),
* (PUCHAR)( pdata + 2 ),
* (PUCHAR)( pdata + 3 )
);
break;
case DNS_TYPE_AAAA:
{
IP6_ADDRESS ip6;
RtlCopyMemory(
&ip6,
pdata,
sizeof(ip6) );
PrintRoutine(
pContext,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
ip6.IP6Word[0],
ip6.IP6Word[1],
ip6.IP6Word[2],
ip6.IP6Word[3],
ip6.IP6Word[4],
ip6.IP6Word[5],
ip6.IP6Word[6],
ip6.IP6Word[7]
);
break;
}
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_MD:
case DNS_TYPE_MB:
case DNS_TYPE_MF:
case DNS_TYPE_MG:
case DNS_TYPE_MR:
//
// these RRs contain single domain name
//
DnsPrint_PacketName(
PrintRoutine,
pContext,
NULL,
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
break;
case DNS_TYPE_MX:
case DNS_TYPE_RT:
case DNS_TYPE_AFSDB:
//
// these RR contain
// - one preference value
// - one domain name
//
PrintRoutine(
pContext,
"%d ",
FlipUnalignedWord( pdata )
);
DnsPrint_PacketName(
PrintRoutine,
pContext,
NULL,
pdata + sizeof(WORD),
pMsgHead,
pMsgEnd,
"\r\n" );
break;
case DNS_TYPE_SOA:
pdata += DnsPrint_PacketName(
PrintRoutine,
pContext,
"\r\n\t\tPrimaryServer: ",
pdata,
pMsgHead,
pMsgEnd,
NULL );
pdata += DnsPrint_PacketName(
PrintRoutine,
pContext,
"\r\n\t\tAdministrator: ",
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
PrintRoutine(
pContext,
"\t\tSerialNo = %d\r\n"
"\t\tRefresh = %d\r\n"
"\t\tRetry = %d\r\n"
"\t\tExpire = %d\r\n"
"\t\tMinimumTTL = %d\r\n",
FlipUnalignedDword( pdata ),
FlipUnalignedDword( (PDWORD)pdata+1 ),
FlipUnalignedDword( (PDWORD)pdata+2 ),
FlipUnalignedDword( (PDWORD)pdata+3 ),
FlipUnalignedDword( (PDWORD)pdata+4 )
);
break;
case DNS_TYPE_MINFO:
case DNS_TYPE_RP:
//
// these RRs contain two domain names
//
pdata += DnsPrint_PacketName(
PrintRoutine,
pContext,
NULL,
pdata,
pMsgHead,
pMsgEnd,
NULL );
DnsPrint_PacketName(
PrintRoutine,
pContext,
" ",
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
break;
case DNS_TYPE_TEXT:
case DNS_TYPE_HINFO:
case DNS_TYPE_ISDN:
case DNS_TYPE_X25:
{
//
// all these are simply text string(s)
//
PCHAR pch = pdata;
PCHAR pchStop = pch + dlen;
UCHAR cch;
while ( pch < pchStop )
{
cch = (UCHAR) *pch++;
PrintRoutine(
pContext,
"\t%.*s\r\n",
cch,
pch );
pch += cch;
}
if ( pch != pchStop )
{
PrintRoutine(
pContext,
"ERROR: Bad RR. "
"Text strings do not add to RR length.\r\n" );
}
break;
}
case DNS_TYPE_WKS:
{
INT i;
PrintRoutine(
pContext,
"WKS: Address %d.%d.%d.%d\r\n"
"\t\tProtocol %d\r\n"
"\t\tBitmask\r\n",
* (PUCHAR)( pdata + 0 ),
* (PUCHAR)( pdata + 1 ),
* (PUCHAR)( pdata + 2 ),
* (PUCHAR)( pdata + 3 ),
* (PUCHAR)( pdata + 4 ) );
pdata += SIZEOF_WKS_FIXED_DATA;
for ( i=0; i < (INT)(dlen-SIZEOF_WKS_FIXED_DATA); i++ )
{
PrintRoutine(
pContext,
"\t\t\tbyte[%d] = %x\r\n",
i,
(UCHAR) pdata[i] );
}
break;
}
case DNS_TYPE_NULL:
DnsPrint_RawOctets(
PrintRoutine,
pContext,
NULL,
"\t\t",
pdata,
dlen );
break;
case DNS_TYPE_SRV:
// SRV <priority> <weight> <port> <target host>
PrintRoutine(
pContext,
"\t\tPriority = %d\r\n"
"\t\tWeight = %d\r\n"
"\t\tPort = %d\r\n",
FlipUnalignedWord( pdata ),
FlipUnalignedWord( (PWORD)pdata+1 ),
FlipUnalignedWord( (PWORD)pdata+2 )
);
DnsPrint_PacketName(
PrintRoutine,
pContext,
"\t\tTarget host ",
pdata + 3*sizeof(WORD),
pMsgHead,
pMsgEnd,
"\r\n" );
break;
case DNS_TYPE_OPT:
//
// OPT
// - RR class is buffer size
// - RR TTL contains
// <extended RCODE> low byte
// <version> second byte
// <flags-zero> high word
//
{
BYTE version;
BYTE extendedRcode;
DWORD fullRcode = 0;
WORD flags;
extendedRcode = *( (PBYTE) &pMsgRR->TimeToLive );
version = *( (PBYTE) &pMsgRR->TimeToLive + 1 );
flags = *( (PWORD) &pMsgRR->TimeToLive + 1 );
if ( pMsgHead->ResponseCode )
{
fullRcode = ((DWORD)extendedRcode << 4) +
(DWORD)pMsgHead->ResponseCode;
}
PrintRoutine(
pContext,
"\t\tBuffer Size = %d\r\n"
"\t\tRcode Ext = %d (%x)\r\n"
"\t\tRcode Full = %d\r\n"
"\t\tVersion = %d\r\n"
"\t\tFlags = %x\r\n",
FlipUnalignedWord( &pMsgRR->RecordClass ),
extendedRcode, extendedRcode,
fullRcode,
version,
flags );
}
break;
case DNS_TYPE_TKEY:
{
DWORD beginTime;
DWORD expireTime;
WORD keyLength;
WORD mode;
WORD extRcode;
WORD otherLength;
otherLength = (WORD)DnsPrint_PacketName(
PrintRoutine,
pContext,
"\r\n\t\tAlgorithm: ",
pdata,
pMsgHead,
pMsgEnd,
NULL );
if ( !otherLength )
{
PrintRoutine(
pContext,
"Invalid algorithm name in TKEY RR!\r\n" );
}
pdata += otherLength;
beginTime = InlineFlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
expireTime = InlineFlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
mode = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
extRcode = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
keyLength = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
PrintRoutine(
pContext,
"\r\n"
"\t\tCreate time = %d\r\n"
"\t\tExpire time = %d\r\n"
"\t\tMode = %d\r\n"
"\t\tExtended RCODE = %d\r\n"
"\t\tKey Length = %d\r\n",
beginTime,
expireTime,
mode,
extRcode,
keyLength );
if ( pdata + keyLength > pdataStop )
{
PrintRoutine(
pContext,
"Invalid key length: exceeds record data!\r\n" );
break;
}
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tKey:",
"\t\t ", // line header
pdata,
keyLength );
pdata += keyLength;
if ( pdata + sizeof(WORD) > pdataStop )
{
break;
}
otherLength = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
PrintRoutine(
pContext,
"\r\n"
"\t\tOther Length = %d\r\n",
otherLength );
if ( pdata + otherLength > pdataStop )
{
PrintRoutine(
pContext,
"Invalid other data length: exceeds record data!\r\n" );
break;
}
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tOther Data:",
"\t\t ", // line header
pdata,
otherLength );
break;
}
case DNS_TYPE_TSIG:
{
ULONGLONG signTime;
WORD fudgeTime;
WORD sigLength;
WORD extRcode;
WORD wOriginalId;
WORD otherLength;
otherLength = (WORD) DnsPrint_PacketName(
PrintRoutine,
pContext,
"\r\n\t\tAlgorithm: ",
pdata,
pMsgHead,
pMsgEnd,
NULL );
if ( !otherLength )
{
PrintRoutine(
pContext,
"Invalid algorithm name in TSIG RR!\r\n" );
}
pdata += otherLength;
signTime = InlineFlipUnaligned48Bits( pdata );
pdata += sizeof(DWORD) + sizeof(WORD);
fudgeTime = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
sigLength = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
PrintRoutine(
pContext,
"\r\n"
"\t\tSigned time = %I64u\r\n"
"\t\tFudge time = %u\r\n"
"\t\tSig Length = %u\r\n",
signTime,
fudgeTime,
sigLength );
if ( pdata + sigLength > pdataStop )
{
PrintRoutine(
pContext,
"Invalid signature length: exceeds record data!\r\n" );
break;
}
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tSignature:",
"\t\t ", // line header
pdata,
sigLength );
pdata += sigLength;
if ( pdata + sizeof(DWORD) > pdataStop )
{
break;
}
wOriginalId = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
extRcode = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
otherLength = InlineFlipUnalignedWord( pdata );
pdata += sizeof(WORD);
PrintRoutine(
pContext,
"\r\n"
"\t\tOriginal XID = %x\r\n"
"\t\tExtended RCODE = %u\r\n"
"\t\tOther Length = %u\r\n",
wOriginalId,
extRcode,
otherLength );
if ( pdata + otherLength > pdataStop )
{
PrintRoutine(
pContext,
"Invalid other data length: exceeds record data!\r\n" );
break;
}
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tOther Data:",
"\t\t ", // line header
pdata,
otherLength );
break;
}
case DNS_TYPE_WINS:
{
DWORD i;
DWORD winsFlags;
DWORD lookupTimeout;
DWORD cacheTimeout;
DWORD winsCount;
CHAR flagString[ WINS_FLAG_MAX_LENGTH ];
//
// WINS
// - scope/domain mapping flag
// - lookup timeout
// - cache timeout
// - WINS server count
// - WINS server list
//
winsFlags = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
lookupTimeout = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
cacheTimeout = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
winsCount = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
Dns_WinsRecordFlagString(
winsFlags,
flagString );
PrintRoutine(
pContext,
"\r\n"
"\t\tWINS flags = %s (%08x)\r\n"
"\t\tLookup timeout = %d\r\n"
"\t\tCaching TTL = %d\r\n",
flagString,
winsFlags,
lookupTimeout,
cacheTimeout );
if ( pdata + (winsCount * SIZEOF_IP_ADDRESS) > pdataStop )
{
PrintRoutine(
pContext,
"ERROR: WINS server count leads beyond record data length!\n"
"\tpmsg = %p\n"
"\tpmsgEnd = %p\n"
"\tpRR = %p\n"
"\trecord data end = %p\n"
"\twins count = %d\n"
"\tend of wins IPs = %p\n",
pMsgHead,
pMsgEnd,
pMsgRR,
pdataStop,
winsCount,
pdata + (winsCount * SIZEOF_IP_ADDRESS)
);
goto Done;
}
DnsPrint_IpAddressArray(
PrintRoutine,
pContext,
NULL,
"\tWINS",
winsCount,
(PIP_ADDRESS) pdata );
break;
}
case DNS_TYPE_WINSR:
{
DWORD winsFlags;
DWORD lookupTimeout;
DWORD cacheTimeout;
CHAR flagString[ WINS_FLAG_MAX_LENGTH ];
//
// NBSTAT
// - scope/domain mapping flag
// - lookup timeout
// - cache timeout
// - result domain -- optional
//
winsFlags = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
lookupTimeout = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
cacheTimeout = FlipUnalignedDword( pdata );
pdata += sizeof(DWORD);
Dns_WinsRecordFlagString(
winsFlags,
flagString );
PrintRoutine(
pContext,
"\r\n"
"\t\tWINS-R flags = %s (%08x)\r\n"
"\t\tLookup timeout = %d\r\n"
"\t\tCaching TTL = %d\r\n",
flagString,
winsFlags,
lookupTimeout,
cacheTimeout );
DnsPrint_PacketName(
PrintRoutine,
pContext,
"\t\tResult domain = ",
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
break;
}
case DNS_TYPE_KEY:
{
WORD flags;
BYTE protocol;
BYTE algorithm;
INT keyLength;
CHAR szKeyFlags[ 100 ];
keyLength = dlen - SIZEOF_KEY_FIXED_DATA;
flags = FlipUnalignedWord( pdata );
pdata += sizeof( WORD );
protocol = * ( PBYTE ) pdata;
++pdata;
algorithm = * ( PBYTE ) pdata;
++pdata;
PrintRoutine(
pContext,
"\r\n"
"\t\tKEY flags = 0x%04x %s\r\n"
"\t\tKEY protocol = %s (%d)\r\n"
"\t\tKEY algorithm = %s (%d)\r\n",
(INT) flags,
Dns_KeyFlagString( szKeyFlags, flags ),
Dns_GetKeyProtocolString( protocol ),
(INT) protocol,
Dns_GetDnssecAlgorithmString( algorithm ),
(INT) algorithm );
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tPublic key:",
"\t\t ", // line header
pdata,
keyLength );
break;
}
case DNS_TYPE_SIG:
{
WORD typeCovered;
BYTE algorithm;
BYTE labelCount;
DWORD originalTTL;
DWORD sigInception;
DWORD sigExpiration;
WORD keyTag;
CHAR szSigInception[ 100 ];
CHAR szSigExpiration[ 100 ];
INT sigLength;
typeCovered = FlipUnalignedWord( pdata );
pdata += sizeof( WORD );
algorithm = * ( PBYTE ) pdata;
++pdata;
labelCount = * ( PBYTE ) pdata;
++pdata;
originalTTL = FlipUnalignedDword( pdata );
pdata += sizeof( DWORD );
sigExpiration = FlipUnalignedDword( pdata );
pdata += sizeof( DWORD );
sigInception = FlipUnalignedDword( pdata );
pdata += sizeof( DWORD );
keyTag = FlipUnalignedWord( pdata );
pdata += sizeof( WORD );
PrintRoutine(
pContext,
"\r\n"
"\t\tSIG type covered = %s\r\n"
"\t\tSIG algorithm = %s (%d)\r\n"
"\t\tSIG label count = %d\r\n"
"\t\tSIG original TTL = %d\r\n"
"\t\tSIG expiration = %s\r\n"
"\t\tSIG inception = %s\r\n"
"\t\tSIG key tag = %d\r\n",
Dns_RecordStringForType( typeCovered ),
Dns_GetDnssecAlgorithmString( ( BYTE ) algorithm ),
( INT ) algorithm,
( INT ) labelCount,
( INT ) originalTTL,
Dns_SigTimeString( sigExpiration, szSigExpiration ),
Dns_SigTimeString( sigInception, szSigInception ),
( INT ) keyTag );
pdata += DnsPrint_PacketName(
PrintRoutine,
pContext,
"\t\tSIG signer's name = ",
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
sigLength = ( INT ) ( pdataStop - pdata );
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"\t\tSignature:",
"\t\t ", // line header
pdata,
sigLength );
break;
}
case DNS_TYPE_NXT:
{
INT bitmapLength;
INT byteIdx;
INT bitIdx;
pdata += DnsPrint_PacketName(
PrintRoutine,
pContext,
"\r\n\t\tNXT next name = ",
pdata,
pMsgHead,
pMsgEnd,
"\r\n" );
bitmapLength = ( INT ) ( pdataStop - pdata );
PrintRoutine( pContext, "\t\tNXT types covered = " );
for ( byteIdx = 0; byteIdx < bitmapLength; ++byteIdx )
{
for ( bitIdx = ( byteIdx ? 0 : 1 ); bitIdx < 8; ++bitIdx )
{
PCHAR pszType;
if ( !( pdata[ byteIdx ] & ( 1 << bitIdx ) ) )
{
continue; // Bit value is zero - do not write string.
}
pszType = Dns_RecordStringForType( byteIdx * 8 + bitIdx );
if ( !pszType )
{
ASSERT( FALSE );
continue; // This type has no string - do not write.
}
PrintRoutine( pContext, "%s ", pszType );
}
}
PrintRoutine( pContext, "\r\n" );
break;
}
default:
PrintRoutine(
pContext,
"Unknown resource record type %d at %p.\r\n",
type,
pMsgRR );
DnsPrint_RawOctets(
PrintRoutine,
pContext,
NULL,
"\t\t",
pdata,
dlen );
break;
}
Done:
DnsPrint_Unlock();
return( sizeof(DNS_WIRE_RECORD) + dlen );
}
//
// Print related utilities
//
INT
Dns_WriteFormattedSystemTimeToBuffer(
OUT PCHAR pBuffer,
IN PSYSTEMTIME pSystemTime
)
/*++
Routine Description:
Write SYSTEMTIME structure to buffer.
Arguments:
pBuffer -- buffer to write into, assumed to have at least 50
bytes available
pSystemTime -- system time to convert; assumed to be local, no
time zone conversion is done
Return Value:
Bytes in formatted string.
--*/
{
PCHAR pend = pBuffer + 60;
PCHAR pstart = pBuffer;
INT count;
pBuffer += GetDateFormat(
LOCALE_SYSTEM_DEFAULT,
LOCALE_NOUSEROVERRIDE,
(PSYSTEMTIME) pSystemTime,
NULL,
pBuffer,
(int)(pend - pBuffer) );
// Replace NULL from GetDateFormat with a space.
*( pBuffer - 1 ) = ' ';
pBuffer += GetTimeFormat(
LOCALE_SYSTEM_DEFAULT,
LOCALE_NOUSEROVERRIDE,
(PSYSTEMTIME) pSystemTime,
NULL,
pBuffer,
(int)(pend - pBuffer) );
if ( pBuffer <= pstart+1 )
{
return( 0 );
}
return (INT)( pBuffer - pstart );
}
//
// Response code print
//
#define DNS_RCODE_UNKNOWN (DNS_RCODE_BADTIME + 1)
PCHAR ResponseCodeStringTable[] =
{
"NOERROR",
"FORMERR",
"SERVFAIL",
"NXDOMAIN",
"NOTIMP",
"REFUSED",
"YXDOMAIN",
"YXRRSET",
"NXRRSET",
"NOTAUTH",
"NOTZONE",
"11 - unknown\r\n",
"12 - unknown\r\n",
"13 - unknown\r\n",
"14 - unknown\r\n",
"15 - unknown\r\n",
// DNS RCODEs stop at 15 -- these extended errors are available for security
"BADSIG",
"BADKEY",
"BADTIME",
"UNKNOWN"
};
PCHAR
Dns_ResponseCodeString(
IN INT ResponseCode
)
/*++
Routine Description:
Get string corresponding to a response code.
Arguments:
ResponseCode - response code
Return Value:
Ptr to string for code.
--*/
{
if ( ResponseCode > DNS_RCODE_UNKNOWN )
{
ResponseCode = DNS_RCODE_UNKNOWN;
}
return( ResponseCodeStringTable[ ResponseCode ] );
}
//
// More detailed RCODE strings
//
PCHAR ResponseCodeExplanationStringTable[] =
{
"NOERROR: no error",
"FORMERR: format error",
"SERVFAIL: server failure",
"NXDOMAIN: name error",
"NOTIMP: not implemented",
"REFUSED",
"YXDOMAIN: name exists that should not",
"YXRRSET: RR set exists that should not",
"NXRRSET: required RR set does not exist",
"NOTAUTH: not authoritative",
"NOTZONE: name not in zone",
"11 - unknown",
"12 - unknown",
"13 - unknown",
"14 - unknown",
"15 - unknown",
// DNS RCODEs stop at 15 -- these extended errors are available for security
"BADSIG: bad signature",
"BADKEY: bad signature",
"BADTIME: invalid or expired time on signature or key",
"UNKNOWN"
};
PCHAR
Dns_ResponseCodeExplanationString(
IN INT ResponseCode
)
/*++
Routine Description:
Get string corresponding to a response code.
Basically for use by packet debug routine above.
Arguments:
ResponseCode - response code
Return Value:
Ptr to string for code.
--*/
{
if ( ResponseCode > DNS_RCODE_UNKNOWN )
{
ResponseCode = DNS_RCODE_UNKNOWN;
}
return( ResponseCodeExplanationStringTable[ ResponseCode ] );
}
PCHAR
Dns_KeyFlagString(
IN OUT PCHAR pszBuff,
IN WORD Flags
)
/*++
Routine Description:
Formats a human-readable string based on the flags value
(DNSSEC KEY RR flags). See RFC2535 section 3.2.1.
Arguments:
pszBuff - buffer to dump string into should be min 100 chars
flags - flag value to generate string for
Return Value:
pszBuff
--*/
{
BOOL fZoneKey = FALSE;
*pszBuff = '\0';
// "type" bits
if ( ( Flags & 0xC000 ) == 0xC000 )
{
strcat( pszBuff, "NOKEY " );
}
else if ( ( Flags & 0xC000 ) == 0x8000 )
{
strcat( pszBuff, "NOAUTH " );
}
else if ( ( Flags & 0xC000 ) == 0x4000 )
{
strcat( pszBuff, "NOCONF " );
}
else
{
strcat( pszBuff, "NOAUTH NOCONF " );
}
// extended bit
if ( Flags & 0x1000 )
{
strcat( pszBuff, "EXTEND " );
}
// name type bits
if ( ( Flags & 0x0300 ) == 0x0300 )
{
strcat( pszBuff, "RESNT " ); // reserved name type
}
else if ( ( Flags & 0x0200 ) == 0x0100 )
{
strcat( pszBuff, "ENTITY " );
}
else if ( ( Flags & 0x0100 ) == 0x4000 )
{
strcat( pszBuff, "ZONE " );
fZoneKey = TRUE;
}
else
{
strcat( pszBuff, "USER " );
}
// signatory bits
if ( fZoneKey )
{
strcat( pszBuff, ( Flags & 0x0008 ) ? "MODEA " : "MODEB " );
if ( Flags & 0x0004 )
{
strcat( pszBuff, "STRONG " );
}
if ( Flags & 0x0002 )
{
strcat( pszBuff, "UNIQ " );
}
}
else
{
if ( Flags & 0x0008 )
{
strcat( pszBuff, "ZCTRL " );
}
if ( Flags & 0x0004 )
{
strcat( pszBuff, "STRONG " );
}
if ( Flags & 0x0002 )
{
strcat( pszBuff, "UNIQ " );
}
}
return pszBuff;
}
//
// Opcode print
//
PCHAR OpcodeStringTable[] =
{
"QUERY",
"IQUERY",
"SRV_STATUS",
"UNKNOWN",
"NOTIFY",
"UPDATE",
"UNKNOWN?"
};
CHAR OpcodeCharacterTable[] =
{
'Q',
'I',
'S',
'K',
'N',
'U',
'?'
};
#define DNS_OPCODE_UNSPEC (DNS_OPCODE_UPDATE + 1)
PCHAR
Dns_OpcodeString(
IN INT Opcode
)
/*++
Routine Description:
Get string corresponding to a response code.
Arguments:
Opcode - response code
Return Value:
Ptr to string for code.
--*/
{
if ( Opcode > DNS_OPCODE_UNSPEC )
{
Opcode = DNS_OPCODE_UNSPEC;
}
return( OpcodeStringTable[ Opcode ] );
}
CHAR
Dns_OpcodeCharacter(
IN INT Opcode
)
/*++
Routine Description:
Get string corresponding to an opcode.
Arguments:
Opcode - response code
Return Value:
Ptr to string for code.
--*/
{
if ( Opcode > DNS_OPCODE_UNSPEC )
{
Opcode = DNS_OPCODE_UNSPEC;
}
return( OpcodeCharacterTable[ Opcode ] );
}
//
// Section names
//
// With update get a new set of section names.
// Provide single interface to putting a name on them.
//
PSTR SectionNameArray[5] =
{
"Question",
"Answer",
"Authority",
"Additional",
"ERROR: Invalid Section"
};
PSTR UpdateSectionNameArray[5] =
{
"Zone",
"Prerequisite",
"Update",
"Additional",
"ERROR: Invalid Section"
};
PCHAR
Dns_SectionNameString(
IN INT iSection,
IN INT iOpcode
)
/*++
Routine Description:
Get string corresponding to name of RR section id.
For use by packet debug routine above.
Arguments:
iSection - section id (0-3 for Question-Additional)
iOpcode - opcode
Return Value:
Ptr to string for section name.
--*/
{
if ( iSection >= 4 )
{
iSection = 4;
}
if ( iOpcode == DNS_OPCODE_UPDATE )
{
return( UpdateSectionNameArray[iSection] );
}
else
{
return( SectionNameArray[iSection] );
}
}
VOID
DnsPrint_MessageNoContext(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_HEADER pMsgHead,
IN WORD wLength OPTIONAL
)
/*++
Routine Description:
Print DNS message buffer.
Includes context information as well as actual DNS message.
--*/
{
PCHAR pchRecord;
PBYTE pmsgEnd;
INT i;
INT isection;
INT cchName;
WORD wOffset;
WORD wXid;
WORD wQuestionCount;
WORD wAnswerCount;
WORD wNameServerCount;
WORD wAdditionalCount;
WORD countSectionRR;
BOOL fFlipped = FALSE;
//
// processing limits
// - if length given set stop limit
// - if length not given set wLength so checks against
// length overrun always fail (are ok)
//
if ( wLength )
{
pmsgEnd = ((PBYTE)pMsgHead) + wLength;
}
else
{
wLength = MAXWORD;
pmsgEnd = NULL;
}
DnsPrint_Lock();
if ( pszHeader )
{
PrintRoutine( pContext, "%s\r\n", pszHeader );
}
PrintRoutine(
pContext,
"DNS message header at %p\r\n",
pMsgHead );
PrintRoutine(
pContext,
" XID 0x%04hx\r\n"
" Flags 0x%04hx\r\n"
" QR 0x%lx (%s)\r\n"
" OPCODE 0x%lx (%s)\r\n"
" AA 0x%lx\r\n"
" TC 0x%lx\r\n"
" RD 0x%lx\r\n"
" RA 0x%lx\r\n"
" Z 0x%lx\r\n"
" RCODE 0x%lx (%s)\r\n"
" QCOUNT 0x%hx\r\n"
" ACOUNT 0x%hx\r\n"
" NSCOUNT 0x%hx\r\n"
" ARCOUNT 0x%hx\r\n",
pMsgHead->Xid,
ntohs((*((PWORD)pMsgHead + 1))),
pMsgHead->IsResponse,
(pMsgHead->IsResponse ? "response" : "question"),
pMsgHead->Opcode,
Dns_OpcodeString( pMsgHead->Opcode ),
pMsgHead->Authoritative,
pMsgHead->Truncation,
pMsgHead->RecursionDesired,
pMsgHead->RecursionAvailable,
pMsgHead->Reserved,
pMsgHead->ResponseCode,
Dns_ResponseCodeString( pMsgHead->ResponseCode ),
pMsgHead->QuestionCount,
pMsgHead->AnswerCount,
pMsgHead->NameServerCount,
pMsgHead->AdditionalCount );
//
// determine if byte flipped and get correct count
//
wXid = pMsgHead->Xid;
wQuestionCount = pMsgHead->QuestionCount;
wAnswerCount = pMsgHead->AnswerCount;
wNameServerCount = pMsgHead->NameServerCount;
wAdditionalCount = pMsgHead->AdditionalCount;
if ( wQuestionCount )
{
fFlipped = wQuestionCount & 0xff00;
}
else if ( wNameServerCount )
{
fFlipped = wNameServerCount & 0xff00;
}
if ( fFlipped )
{
wXid = ntohs( wXid );
wQuestionCount = ntohs( wQuestionCount );
wAnswerCount = ntohs( wAnswerCount );
wNameServerCount = ntohs( wNameServerCount );
wAdditionalCount = ntohs( wAdditionalCount );
}
//
// catch record flipping problems -- all are flipped or none at all
// and no record count should be > 256 EXCEPT answer count
// during FAST zone transfer
//
DNS_ASSERT( ! (wQuestionCount & 0xff00) );
DNS_ASSERT( ! (wNameServerCount & 0xff00) );
DNS_ASSERT( ! (wAdditionalCount & 0xff00) );
#if 0
//
// stop here if WINS response -- don't have parsing ready
//
if ( pMsgHead->IsResponse && IS_WINS_XID(wXid) )
{
PrintRoutine( pContext, " WINS Response packet.\r\n\r\n" );
goto Unlock;
}
#endif
//
// print questions and resource records
//
pchRecord = (PCHAR)(pMsgHead + 1);
for ( isection=0; isection<4; isection++)
{
PrintRoutine(
pContext,
" %s Section:\r\n",
Dns_SectionNameString( isection, pMsgHead->Opcode ) );
if ( isection==0 )
{
countSectionRR = wQuestionCount;
}
else if ( isection==1 )
{
countSectionRR = wAnswerCount;
}
else if ( isection==2 )
{
countSectionRR = wNameServerCount;
}
else if ( isection==3 )
{
countSectionRR = wAdditionalCount;
}
for ( i=0; i < countSectionRR; i++ )
{
//
// verify not overrunning length
// - check against pCurrent as well as message length
// so can print packets while being built
//
wOffset = (WORD)(pchRecord - (PCHAR)pMsgHead);
if ( wOffset >= wLength )
{
PrintRoutine(
pContext,
"ERROR: BOGUS PACKET:\r\n"
"\tFollowing RR (offset %d) past packet length (%d).\r\n",
wOffset,
wLength
);
goto Unlock;
}
//
// print RR name
//
PrintRoutine(
pContext,
" Name Offset = 0x%04x\r\n",
wOffset
);
cchName = DnsPrint_PacketName(
PrintRoutine,
pContext,
" Name \"",
pchRecord,
pMsgHead,
pmsgEnd,
"\"\r\n" );
if ( !cchName )
{
PrintRoutine(
pContext,
"ERROR: Invalid name length, stop packet print\r\n" );
DNS_ASSERT( FALSE );
break;
}
pchRecord += cchName;
// print question or resource record
if ( isection == 0 )
{
PrintRoutine(
pContext,
" QTYPE %d\r\n"
" QCLASS %d\r\n",
FlipUnalignedWord( pchRecord ),
FlipUnalignedWord( pchRecord + sizeof(WORD) )
);
pchRecord += sizeof( DNS_WIRE_QUESTION );
}
else
{
pchRecord += DnsPrint_PacketRecord(
PrintRoutine,
pContext,
NULL,
(PDNS_WIRE_RECORD) pchRecord,
pMsgHead,
pmsgEnd
);
}
}
}
// check that at proper end of packet
wOffset = (WORD)(pchRecord - (PCHAR)pMsgHead);
PrintRoutine(
pContext,
" Message length = %04x\r\n\r\n",
wOffset );
// print warning if given message length and did not end up
// at end of message
// note: pmsgEnd test in case passed wLength==0, in which case
// wLength set to MAXDWORD above
if ( pmsgEnd && wOffset < wLength )
{
PrintRoutine(
pContext,
"WARNING: message continues beyond these records\r\n"
"\tpch = %p\r\n"
"\toffset = %d, msg length = %d, %d bytes\r\n",
pchRecord,
wOffset,
wLength,
wLength - wOffset );
DnsPrint_RawOctets(
PrintRoutine,
pContext,
"Remaining bytes:",
NULL,
pchRecord,
(wLength - wOffset) );
}
Unlock:
DnsPrint_Unlock();
} // DnsPrint_MessageNoContext
DWORD
DnsStringPrint_Guid(
OUT PCHAR pBuffer,
IN PGUID pGuid
)
/*++
Routine Description:
Print GUID to buffer.
Arguments:
pBuffer - buffer to print to
buffer must be big enough for GUID string
GUID_STRING_BUFFER_LENGTH covers it
pGuid - GUID to print
Return Value:
Count of bytes printed to string.
--*/
{
if ( !pGuid )
{
*pBuffer = 0;
return 0;
}
return sprintf(
pBuffer,
"%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
*(PWORD) &pGuid->Data4[0],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7],
pGuid->Data4[8] );
}
VOID
DnsPrint_Guid(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PGUID pGuid
)
/*++
Routine Description:
Print GUID
Arguments:
pszHeader - Header message/name for RR.
pGuid -- ptr to GUID to print
Return Value:
None.
--*/
{
CHAR guidBuffer[ GUID_STRING_BUFFER_LENGTH ];
if ( !pszHeader )
{
pszHeader = "Guid";
}
if ( !pGuid )
{
PrintRoutine(
pContext,
"%s: NULL GUID pointer!\r\n",
pszHeader );
}
// convert GUID to string
DnsStringPrint_Guid(
guidBuffer,
pGuid );
PrintRoutine(
pContext,
"%s: (%p) %s\r\n",
pszHeader,
pGuid,
guidBuffer );
}
DWORD
DnsStringPrint_RawOctets(
OUT PCHAR pBuffer,
IN PCHAR pchData,
IN DWORD dwLength,
IN PSTR pszLineHeader,
IN DWORD dwLineLength
)
/*++
Routine Description:
Print raw octect data to sting
Arguments:
pBuffer - buffer to print to
pchData - data to print
dwLength - length of data to print
pszLineHeader - header on each line.
dwLineLength - number of bytes to print on line; default is
Return Value:
Count of bytes printed to string.
--*/
{
INT i;
INT lineCount = 0;
PCHAR pch = pBuffer;
*pch = 0;
//
// catch NULL pointer
// - return is null terminated
// - but indicate no bytes written
//
if ( !pchData )
{
return 0;
}
//
// write each byte in hex
// - if dwLineLength set break into lines with count
// or optional header
//
for ( i = 0; i < (INT)dwLength; i++ )
{
if ( dwLineLength && (i % dwLineLength) == 0 )
{
if ( pszLineHeader )
{
pch += sprintf( pch, "\r\n%s", pszLineHeader );
}
else
{
pch += sprintf( pch, "\r\n%3d> ", i );
}
lineCount++;
}
pch += sprintf( pch, "%02x ", (UCHAR)pchData[i] );
}
return( (DWORD)(pch - pBuffer) );
}
VOID
DnsPrint_RawBinary(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR pszLineHeader,
IN PCHAR pchData,
IN DWORD dwLength,
IN DWORD PrintSize
)
/*++
Routine Description:
Print raw data.
Arguments:
pszHeader - Header message/name for RR.
pszLineHeader - Header on each line.
pchData - data to print
dwLength - length of data to print
PrintSize - size to print in
size(QWORD)
size(DWORD)
size(WORD)
defaults to bytes
Return Value:
None.
--*/
{
DWORD i;
DWORD lineCount = 0;
CHAR buf[ 2000 ];
PCHAR pch = buf;
PCHAR pbyte;
PCHAR pend;
DnsPrint_Lock();
if ( pszHeader )
{
PrintRoutine(
pContext,
"%s",
pszHeader );
}
buf[0] = 0;
//
// print bytes
// - write 16 bytes a line
// - buffer up 10 lines for speed
//
// note: we'll write a partial (<16 byte) line the first
// time if data is unaligned with PrintSize, then we'll
// write at 16 a pop
//
if ( PrintSize == 0 )
{
PrintSize = 1;
}
i = 0;
pch = buf;
pend = (PBYTE)pchData + dwLength;
while ( i < dwLength )
{
DWORD lineBytes = (i%16);
if ( lineBytes==0 || lineBytes > (16-PrintSize) )
{
if ( lineCount > 10 )
{
PrintRoutine( pContext, buf );
lineCount = 0;
pch = buf;
}
if ( pszLineHeader )
{
pch += sprintf( pch, "\r\n%s", pszLineHeader );
}
else
{
pch += sprintf( pch, "\r\n\t%3d> ", i );
}
lineCount++;
//if ( i >= 128 && dlen > 256 )
//{
// PrintRoutine( pContext, "skipping remaining bytes ...\r\n" ));
//}
}
pbyte = &pchData[i];
if ( PrintSize == sizeof(QWORD) &&
POINTER_IS_ALIGNED( pbyte, ALIGN_QUAD ) &&
pbyte + sizeof(QWORD) <= pend )
{
pch += sprintf( pch, "%I64x ", *(PQWORD)pbyte );
i += sizeof(QWORD);
}
else if ( PrintSize == sizeof(DWORD) &&
POINTER_IS_ALIGNED( pbyte, ALIGN_DWORD ) &&
pbyte + sizeof(DWORD) <= pend )
{
pch += sprintf( pch, "%08x ", *(PDWORD)pbyte );
i += sizeof(DWORD);
}
else if ( PrintSize == sizeof(WORD) &&
POINTER_IS_ALIGNED( pbyte, ALIGN_WORD ) &&
pbyte + sizeof(WORD) <= pend )
{
pch += sprintf( pch, "%04x ", *(PWORD)pbyte );
i += sizeof(WORD);
}
else // default to byte print
{
pch += sprintf( pch, "%02x ", *pbyte );
i++;
}
}
// print remaining bytes in buffer
PrintRoutine(
pContext,
"%s\r\n",
buf );
DnsPrint_Unlock();
}
VOID
DnsPrint_RawOctets(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PSTR pszLineHeader,
IN PCHAR pchData,
IN DWORD dwLength
)
/*++
Routine Description:
Print raw octect data.
Arguments:
pszHeader - Header message/name for RR.
pszLineHeader - Header on each line.
pchData - data to print
dwLength - length of data to print
Return Value:
None.
--*/
{
INT i;
INT lineCount = 0;
CHAR buf[ 2000 ];
PCHAR pch = buf;
DnsPrint_Lock();
if ( pszHeader )
{
PrintRoutine(
pContext,
"%s",
pszHeader );
}
buf[0] = 0;
// buffer every 20 lines for speed
for ( i = 0; i < (INT)dwLength; i++ )
{
if ( !(i%16) )
{
if ( lineCount > 10 )
{
PrintRoutine( pContext, buf );
lineCount = 0;
pch = buf;
}
if ( pszLineHeader )
{
pch += sprintf( pch, "\r\n%s", pszLineHeader );
}
else
{
pch += sprintf( pch, "\r\n%3d> ", i );
}
lineCount++;
//if ( i >= 128 && dlen > 256 )
//{
// PrintRoutine( pContext, "skipping remaining bytes ...\r\n" ));
//}
}
pch += sprintf( pch, "%02x ", (UCHAR)pchData[i] );
}
// print remaining bytes in buffer
PrintRoutine(
pContext,
"%s\r\n",
buf );
DnsPrint_Unlock();
}
VOID
DnsPrint_ParsedRecord(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_PARSED_RR pParsedRR
)
/*++
Routine Description:
Print parsed RR structure.
Arguments:
pszHeader - Header message/name for RR.
pParsedRR - parsed RR to print
Return Value:
None.
--*/
{
if ( !pszHeader )
{
pszHeader = "Parsed RR:";
}
if ( !pParsedRR )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL ParsedRR ptr." );
return;
}
PrintRoutine(
pContext,
"%s\r\n"
"\tpchName = %p\r\n"
"\tpchRR = %p\r\n"
"\tpchData = %p\r\n"
"\tpchNextRR = %p\r\n"
"\twType = %d\r\n"
"\twClass = %d\r\n"
"\tTTL = %d\r\n"
"\twDataLength = %d\r\n",
pszHeader,
pParsedRR->pchName,
pParsedRR->pchRR,
pParsedRR->pchData,
pParsedRR->pchNextRR,
pParsedRR->Type,
pParsedRR->Class,
pParsedRR->Ttl,
pParsedRR->DataLength
);
}
//
// Winsock RnR structures
//
VOID
DnsPrint_FdSet(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN struct fd_set * pfd_set
)
/*++
Routine Description:
Print sockets in FD_SET.
--*/
{
INT count;
INT i;
DNS_ASSERT( pfd_set );
count = (INT) pfd_set->fd_count;
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s (count = %d)\r\n",
pszHeader ? pszHeader : "FD_SET:",
count );
for (i=0; i<count; i++)
{
PrintRoutine(
pContext,
"\tsocket[%d] = %d\r\n",
i,
pfd_set->fd_array[i] );
}
DnsPrint_Unlock();
}
VOID
DnsPrint_Sockaddr(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN DWORD Indent,
IN PSOCKADDR pSockaddr,
IN INT iSockaddrLength
)
/*++
Routine Description:
Print sockaddr structure and length used in call.
--*/
{
PSTR pindent = INDENT_STRING( Indent );
if ( !pszHeader )
{
pszHeader = "Sockaddr:";
}
if ( !pSockaddr )
{
PrintRoutine(
pContext,
"%s%s\tNULL Sockaddr passed to print.\r\n",
pindent,
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s%s\r\n"
"%s\tpointer = %p\r\n"
"%s\tlength = %d\r\n"
"%s\tsa_family = %d\r\n",
pindent, pszHeader,
pindent, pSockaddr,
pindent, iSockaddrLength,
pindent, pSockaddr->sa_family
);
switch ( pSockaddr->sa_family )
{
case AF_INET:
{
PSOCKADDR_IN psin = (PSOCKADDR_IN) pSockaddr;
PrintRoutine(
pContext,
"%s\tsin_port = %04x\r\n"
"%s\tsin_addr = %s (%08x)\r\n"
"%s\tsin_zero = %08x %08x\r\n",
pindent, psin->sin_port,
pindent, inet_ntoa( psin->sin_addr ),
psin->sin_addr.s_addr,
pindent, *(PDWORD) &psin->sin_zero[0],
*(PDWORD) &psin->sin_zero[4]
);
break;
}
case AF_INET6:
{
PSOCKADDR_IN6 psin = (PSOCKADDR_IN6) pSockaddr;
CHAR buffer[ IP6_ADDRESS_STRING_BUFFER_LENGTH ];
Dns_Ip6AddressToString_A(
buffer,
(PIP6_ADDRESS) &psin->sin6_addr );
PrintRoutine(
pContext,
"%s\tsin6_port = %04x\r\n"
"%s\tsin6_flowinfo = %08x\r\n"
"%s\tsin6_addr = %s\r\n"
"%s\tsin6_scope_id = %08x\r\n",
pindent, psin->sin6_port,
pindent, psin->sin6_flowinfo,
pindent, buffer,
pindent, psin->sin6_scope_id
);
break;
}
default:
// print unknown in WORDs
// limit print as this is probably a busted sockaddr due to bug
{
DnsPrint_RawBinary(
PrintRoutine,
pContext,
"\tdata: ",
pindent, // line header
pSockaddr->sa_data,
iSockaddrLength < 100
? iSockaddrLength
: 100,
sizeof(WORD)
);
break;
}
}
DnsPrint_Unlock();
}
VOID
DnsPrint_AddrInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN DWORD Indent,
IN PADDRINFO pAddrInfo
)
/*++
Routine Description:
Print ADDRINFO structure.
--*/
{
PSTR pindent = INDENT_STRING( Indent );
if ( !pszHeader )
{
pszHeader = "AddrInfo:";
}
if ( !pAddrInfo )
{
PrintRoutine(
pContext,
"%s%s NULL AddrInfo.\r\n",
pindent,
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s%s\n"
"%s\tPtr = %p\r\n"
"%s\tNext Ptr = %p\r\n"
"%s\tFlags = %08x\r\n"
"%s\tFamily = %d\r\n"
"%s\tSockType = %d\r\n"
"%s\tProtocol = %d\r\n"
"%s\tAddrLength = %d\r\n"
"%s\tName = %s\r\n",
pindent, pszHeader,
pindent, pAddrInfo,
pindent, pAddrInfo->ai_next,
pindent, pAddrInfo->ai_flags,
pindent, pAddrInfo->ai_family,
pindent, pAddrInfo->ai_socktype,
pindent, pAddrInfo->ai_protocol,
pindent, pAddrInfo->ai_addrlen,
pindent, pAddrInfo->ai_canonname
);
DnsPrint_Sockaddr(
PrintRoutine,
pContext,
NULL,
Indent + 1,
pAddrInfo->ai_addr,
pAddrInfo->ai_addrlen );
DnsPrint_Unlock();
}
VOID
DnsPrint_AddrInfoList(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN DWORD Indent,
IN PADDRINFO pAddrInfo
)
/*++
Routine Description:
Print ADDRINFO structure.
--*/
{
PADDRINFO paddr = pAddrInfo;
PSTR pindent = INDENT_STRING( Indent );
//
// list header
//
if ( !pszHeader )
{
pszHeader = "AddrInfo List:";
}
if ( !paddr )
{
PrintRoutine(
pContext,
"%s%s NULL AddrInfo List.\r\n",
pindent,
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s%s\n",
pindent, pszHeader
);
//
// print each ADDRINFO in list
//
while ( paddr )
{
DnsPrint_AddrInfo(
PrintRoutine,
pContext,
NULL,
Indent,
paddr );
paddr = paddr->ai_next;
}
PrintRoutine(
pContext,
"End of AddrInfo list\n\n"
);
DnsPrint_Unlock();
}
VOID
DnsPrint_SocketAddress(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN DWORD Indent,
IN PSOCKET_ADDRESS pSocketAddress
)
/*++
Routine Description:
Print SOCKET_ADDRESS structure.
--*/
{
PSTR pindent = INDENT_STRING( Indent );
if ( !pszHeader )
{
pszHeader = "SocketAddress:";
}
if ( !pSocketAddress )
{
PrintRoutine(
pContext,
"%s%s NULL SocketAddress.\r\n",
pindent,
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s%s\n"
"%s\tpSockaddr = %p\r\n"
"%s\tiSockaddrLength = %d\r\n",
pindent, pszHeader,
pindent, pSocketAddress->lpSockaddr,
pindent, pSocketAddress->iSockaddrLength );
DnsPrint_Sockaddr(
PrintRoutine,
pContext,
NULL,
Indent,
pSocketAddress->lpSockaddr,
pSocketAddress->iSockaddrLength );
DnsPrint_Unlock();
}
VOID
DnsPrint_CsAddr(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN DWORD Indent,
IN PCSADDR_INFO pCsAddr
)
/*++
Routine Description:
Print CSADDR_INFO structure.
Arguments:
PrintRoutine - routine to print with
pParam - ptr to print context
pszHeader - header
Indent - indent count, for formatting CSADDR inside larger struct
pCsAddr - ptr to CSADDRINFO to print
Return Value:
None.
--*/
{
PSTR pindent = INDENT_STRING( Indent );
if ( !pszHeader )
{
pszHeader = "CSAddrInfo:";
}
if ( !pCsAddr )
{
PrintRoutine(
pContext,
"%s%s \tNULL CSADDR_INFO ptr.\r\n",
pindent, pszHeader
);
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s%s\r\n"
"%s\tPtr = %p\n"
"%s\tSocketType = %d\n"
"%s\tProtocol = %d\n",
pindent, pszHeader,
pindent, pCsAddr,
pindent, pCsAddr->iSocketType,
pindent, pCsAddr->iProtocol
);
DnsPrint_SocketAddress(
PrintRoutine,
pContext,
"LocalAddress:",
Indent,
& pCsAddr->LocalAddr
);
DnsPrint_SocketAddress(
PrintRoutine,
pContext,
"RemoteAddress:",
Indent,
& pCsAddr->RemoteAddr
);
DnsPrint_Unlock();
}
VOID
DnsPrint_AfProtocolsArray(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PAFPROTOCOLS pProtocolArray,
IN DWORD ProtocolCount
)
/*++
Routine Description:
Print AFPROTOCOLS array.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pProtocolArray - protocols array
ProtocolCount - array count
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "AFPROTOCOLS Array:";
}
// print
// - array + count
// - each protocol element
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\tProtocol Array = %p\r\n"
"\tProtocol Count = %d\r\n",
pszHeader,
pProtocolArray,
ProtocolCount );
if ( pProtocolArray )
{
for ( i=0; i<ProtocolCount; i++ )
{
PrintRoutine(
pContext,
"\t\tfamily = %d; proto = %d\r\n",
pProtocolArray[i].iAddressFamily,
pProtocolArray[i].iProtocol );
}
}
DnsPrint_Unlock();
}
VOID
DnsPrint_WsaQuerySet(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN LPWSAQUERYSET pQuerySet,
IN BOOL fUnicode
)
/*++
Routine Description:
Print WSAQUERYSET structure.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pQuerySet - ptr to WSAQUERYSET to print
fUnicode - TRUE if WSAQUERYSET is wide (WSAQUERYSETW)
FALSE if ANSI
Return Value:
None.
--*/
{
CHAR serviceGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
CHAR nameSpaceGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
DWORD i;
if ( !pszHeader )
{
pszHeader = "WSAQuerySet:";
}
if ( !pQuerySet )
{
PrintRoutine(
pContext,
"%s NULL QuerySet ptr\r\n",
pszHeader );
return;
}
// convert GUIDs to strings
DnsStringPrint_Guid(
serviceGuidBuffer,
pQuerySet->lpServiceClassId
);
DnsStringPrint_Guid(
nameSpaceGuidBuffer,
pQuerySet->lpNSProviderId
);
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\tSize = %d\r\n"
"\tServiceInstanceName = %S%s\r\n"
"\tService GUID = (%p) %s\r\n"
"\tWSA version = %p %x %d\r\n"
"\tComment = %S%s\r\n"
"\tName Space = %d %s\r\n"
"\tName Space GUID = (%p) %s\r\n"
"\tContext = %S%s\r\n"
"\tNumberOfProtocols = %d\r\n"
"\tProtocol Array = %p\r\n"
"\tQueryString = %S%s\r\n"
"\tCS Addr Count = %d\r\n"
"\tCS Addr Array = %p\r\n"
"\tOutput Flags = %08x\r\n"
"\tpBlob = %p\r\n",
pszHeader,
pQuerySet->dwSize,
DNSSTRING_WIDE( fUnicode, pQuerySet->lpszServiceInstanceName ),
DNSSTRING_ANSI( fUnicode, pQuerySet->lpszServiceInstanceName ),
pQuerySet->lpServiceClassId,
serviceGuidBuffer,
pQuerySet->lpVersion,
( pQuerySet->lpVersion ) ? pQuerySet->lpVersion->dwVersion : 0,
( pQuerySet->lpVersion ) ? pQuerySet->lpVersion->ecHow : 0,
DNSSTRING_WIDE( fUnicode, pQuerySet->lpszComment ),
DNSSTRING_ANSI( fUnicode, pQuerySet->lpszComment ),
pQuerySet->dwNameSpace,
Dns_GetRnrNameSpaceIdString( pQuerySet->dwNameSpace ),
pQuerySet->lpNSProviderId,
nameSpaceGuidBuffer,
DNSSTRING_WIDE( fUnicode, pQuerySet->lpszContext ),
DNSSTRING_ANSI( fUnicode, pQuerySet->lpszContext ),
pQuerySet->dwNumberOfProtocols,
pQuerySet->lpafpProtocols,
DNSSTRING_WIDE( fUnicode, pQuerySet->lpszQueryString ),
DNSSTRING_ANSI( fUnicode, pQuerySet->lpszQueryString ),
pQuerySet->dwNumberOfCsAddrs,
pQuerySet->lpcsaBuffer,
pQuerySet->dwOutputFlags,
pQuerySet->lpBlob
);
// print address-family\protocols array
if ( pQuerySet->lpafpProtocols )
{
DnsPrint_AfProtocolsArray(
PrintRoutine,
pContext,
"\tAFPROTOCOLS Array:",
pQuerySet->lpafpProtocols,
pQuerySet->dwNumberOfProtocols );
}
// print CSADDR_INFO array
if ( pQuerySet->dwNumberOfCsAddrs &&
pQuerySet->lpcsaBuffer )
{
PrintRoutine(
pContext,
"--- CS_ADDR array:\r\n" );
for ( i=0; i<pQuerySet->dwNumberOfCsAddrs; i++ )
{
DnsPrint_CsAddr(
PrintRoutine,
pContext,
NULL,
1, // indent one level
& pQuerySet->lpcsaBuffer[i] );
}
}
// print blob (the hostent)
//
// DCR_FIX0: need some sort of test for blob type?
// - most blobs are hostent, but some are servent
//
if ( pQuerySet->lpBlob )
{
GUID ianaGuid = SVCID_INET_SERVICEBYNAME;
PrintRoutine(
pContext,
"--- BLOB:\n"
"\tcbSize = %d\r\n"
"\tpBlobData = %p\r\n",
pQuerySet->lpBlob->cbSize,
pQuerySet->lpBlob->pBlobData
);
// note: can't print blob as hostent
// 1) may not be hostent
// 2) is passed with offsets rather than pointers
DnsPrint_RawBinary(
PrintRoutine,
pContext,
NULL,
"\t\t",
pQuerySet->lpBlob->pBlobData,
pQuerySet->lpBlob->cbSize,
sizeof(DWORD)
);
}
DnsPrint_Unlock();
}
VOID
DnsPrint_WsaNsClassInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PWSANSCLASSINFO pInfo,
IN BOOL fUnicode
)
/*++
Routine Description:
Print WSACLASSINFO structure.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pInfo - ptr to WSACLASSINFO to print
fUnicode - TRUE if WSACLASSINFO is wide (WSACLASSINFOW)
FALSE if ANSI
Return Value:
None.
--*/
{
if ( !pszHeader )
{
pszHeader = "WSANsClassInfo:";
}
if ( !pInfo )
{
PrintRoutine(
pContext,
"%s NULL NsClassInfo ptr\r\n",
pszHeader );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\tPtr = %d\r\n"
"\tName = %S%s\r\n"
"\tName Space = %d\r\n"
"\tValue Type = %d\r\n"
"\tValue Size = %d\r\n"
"\tpValue = %p\r\n",
pszHeader,
pInfo,
DNSSTRING_WIDE( fUnicode, pInfo->lpszName ),
DNSSTRING_ANSI( fUnicode, pInfo->lpszName ),
pInfo->dwNameSpace,
pInfo->dwValueType,
pInfo->dwValueSize,
pInfo->lpValue
);
if ( pInfo->lpValue )
{
PrintRoutine(
pContext,
"--- Value:\r\n"
);
DnsPrint_RawBinary(
PrintRoutine,
pContext,
NULL,
"\t\t",
pInfo->lpValue,
pInfo->dwValueSize,
sizeof(BYTE) // print in bytes
);
}
DnsPrint_Unlock();
}
VOID
DnsPrint_WsaServiceClassInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN LPWSASERVICECLASSINFO pInfo,
IN BOOL fUnicode
)
/*++
Routine Description:
Print WSASERVICECLASSINFO structure.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pInfo - ptr to WSASERVICECLASSINFO to print
fUnicode - TRUE if WSASERVICECLASSINFO is wide (WSASERVICECLASSINFOW)
FALSE if ANSI
Return Value:
None.
--*/
{
CHAR serviceClassGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
if ( !pszHeader )
{
pszHeader = "WSAServiceClassInfo:";
}
if ( !pInfo )
{
PrintRoutine(
pContext,
"%s NULL ServiceClassInfo ptr\r\n",
pszHeader );
return;
}
// convert GUID to strings
DnsStringPrint_Guid(
serviceClassGuidBuffer,
pInfo->lpServiceClassId
);
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\tPtr = %p\r\n"
"\tClass GUID = (%p) %s\r\n"
"\tClassName = %S%s\r\n"
"\tClass Info Count = %d\r\n"
"\tClass Info Array = %p\r\n",
pszHeader,
pInfo,
serviceClassGuidBuffer,
DNSSTRING_WIDE( fUnicode, pInfo->lpszServiceClassName ),
DNSSTRING_ANSI( fUnicode, pInfo->lpszServiceClassName ),
pInfo->dwCount,
pInfo->lpClassInfos
);
if ( pInfo->lpClassInfos )
{
DWORD i;
for ( i=0; i<pInfo->dwCount; i++ )
{
DnsPrint_WsaNsClassInfo(
PrintRoutine,
pContext,
NULL, // default header
& pInfo->lpClassInfos[i],
fUnicode
);
}
}
DnsPrint_Unlock();
}
VOID
DnsPrint_Hostent(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PHOSTENT pHostent,
IN BOOL fUnicode
)
/*++
Routine Description:
Print hostent structure.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pHostent - ptr to hostent
fUnicode - TRUE if hostent is unicode
FALSE if ANSI
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Hostent:";
}
if ( !pHostent )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Hostent ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\th_name = %p %S%s\n"
"\th_aliases = %p\n"
"\th_addrtype = %d\n"
"\th_length = %d\n"
"\th_addrlist = %p\n",
pszHeader,
pHostent->h_name,
DNSSTRING_WIDE( fUnicode, pHostent->h_name ),
DNSSTRING_ANSI( fUnicode, pHostent->h_name ),
pHostent->h_aliases,
pHostent->h_addrtype,
pHostent->h_length,
pHostent->h_addr_list
);
// print the aliases
if ( pHostent->h_aliases )
{
PSTR * paliasArray = pHostent->h_aliases;
PSTR palias;
while ( palias = *paliasArray++ )
{
PrintRoutine(
pContext,
"\tAlias = (%p) %S%s\n",
palias,
DNSSTRING_WIDE( fUnicode, palias ),
DNSSTRING_ANSI( fUnicode, palias ) );
}
}
// print the addresses
if ( pHostent->h_addr_list )
{
PCHAR * ppaddr = pHostent->h_addr_list;
PCHAR pip;
INT i = 0;
INT family = pHostent->h_addrtype;
INT addrLength = pHostent->h_length;
CHAR stringBuf[ IP6_ADDRESS_STRING_BUFFER_LENGTH ];
while ( pip = ppaddr[i] )
{
DWORD bufLength = IP6_ADDRESS_STRING_BUFFER_LENGTH;
Dns_AddressToString_A(
stringBuf,
& bufLength,
pip,
addrLength,
family );
PrintRoutine(
pContext,
"\tAddr[%d] = %s \t(ptr=%p)\n",
i,
stringBuf,
pip );
i++;
}
}
DnsPrint_Unlock();
}
//
// Query print routines
//
VOID
DnsPrint_QueryBlob(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PQUERY_BLOB pBlob
)
/*++
Routine Description:
Print query blob.
Arguments:
PrintRoutine - routine to print with
pContext - print context
pszHeader - header
pBlob - query info
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Query Blob:";
}
if ( !pBlob )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Query Blob ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"\tname orig %S\n"
"\tname orig wire %s\n"
"\tname wire %s\n"
"\ttype %d\n"
"\tflags %08x\n"
"\tname length %d\n"
"\tname attributes %08x\n"
"\tquery count %d\n"
"\tname flags %08x\n"
"\tfappendedName %d\n"
"\tstatus %d\n"
"\trcode %d\n"
"\tnetfail status %d\n"
"\tcache negative %d\n"
"\tno ip local %d\n"
"\trecords %p\n"
"\tlocal records %p\n"
"\tnetwork info %p\n"
"\tserver IPs %p\n"
"\tpmsg %p\n"
"\tevent %p\n",
pBlob->pNameOrig,
pBlob->pNameOrigWire,
pBlob->pNameWire,
pBlob->wType,
pBlob->Flags,
pBlob->NameLength,
pBlob->NameAttributes,
pBlob->QueryCount,
pBlob->NameFlags,
pBlob->fAppendedName,
pBlob->Status,
pBlob->Rcode,
pBlob->NetFailureStatus,
pBlob->fCacheNegative,
pBlob->fNoIpLocal,
pBlob->pRecords,
pBlob->pLocalRecords,
pBlob->pNetworkInfo,
pBlob->pDnsServers,
pBlob->pRecvMsg,
pBlob->hEvent
);
// DCR_FIX0: cleanup when results in use
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Records:\n",
pBlob->pRecords );
// DCR_FIX0: use results when ready
DnsPrint_Unlock();
}
VOID
DnsPrint_QueryResults(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_RESULTS pResults
)
/*++
Routine Description:
Print query results.
Arguments:
PrintRoutine - routine to print with
pContext - print context
pszHeader - header
pResults - results info
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Results:";
}
if ( !pResults )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Results ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"\tstatus %d\n"
"\trcode %d\n"
"\tserver %s\n"
"\tpanswer %p\n"
"\tpalias %p\n"
"\tpauthority %p\n"
"\tpadditional %p\n"
"\tpsig %p\n"
"\tpmsg %p\n",
pResults->Status,
pResults->Rcode,
IP_STRING( pResults->ServerIp ),
pResults->pAnswerRecords,
pResults->pAliasRecords,
pResults->pAuthorityRecords,
pResults->pAdditionalRecords,
pResults->pSigRecords,
pResults->pMessage
);
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"\tAnswer records:\n",
pResults->pAnswerRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"\tAlias records:\n",
pResults->pAliasRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"\tAuthority records:\n",
pResults->pAuthorityRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"\tAdditional records:\n",
pResults->pAdditionalRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"\tSignature records:\n",
pResults->pSigRecords );
DnsPrint_Unlock();
}
VOID
DnsPrint_ParsedMessage(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_PARSED_MESSAGE pParsed
)
/*++
Routine Description:
Print parsed message.
Arguments:
PrintRoutine - routine to print with
pContext - print context
pszHeader - header
pResults - query info
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Parsed Message:";
}
if ( !pParsed )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Parsed Message ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"\tstatus %d (%08x)\n"
"\tchar set %d\n",
pParsed->Status, pParsed->Status,
pParsed->CharSet
);
PrintRoutine(
pContext,
"\tquestion:\n"
"\t\tname %S%s\n"
"\t\ttype %d\n"
"\t\tclass %d\n",
PRINT_STRING_WIDE_CHARSET( pParsed->pQuestionName, pParsed->CharSet ),
PRINT_STRING_ANSI_CHARSET( pParsed->pQuestionName, pParsed->CharSet ),
pParsed->QuestionType,
pParsed->QuestionClass
);
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Answer records:\n",
pParsed->pAnswerRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Alias records:\n",
pParsed->pAliasRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Authority records:\n",
pParsed->pAuthorityRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Additional records:\n",
pParsed->pAdditionalRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Signature records:\n",
pParsed->pSigRecords );
DnsPrint_Unlock();
}
VOID
DnsPrint_QueryInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PDNS_QUERY_INFO pQueryInfo
)
/*++
Routine Description:
Print query info
Arguments:
PrintRoutine - routine to print with
pContext - print context
pszHeader - header
pQueryInfo - query info
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Query Info:";
}
if ( !pQueryInfo )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Query Info ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\n"
"\tpointer %p\n"
"\tstatus %d (%08x)\n"
"\tchar set %d\n"
"\tname %S%s\n"
"\tname resv. %s\n"
"\ttype %d\n"
"\trcode %d\n"
"\tflags %08x\n"
"\tpanswer %p\n"
"\tpalias %p\n"
"\tpauthority %p\n"
"\tpadditional %p\n"
//"\tpsig %p\n"
"\tevent %p\n"
"\tpDnsServers %p\n"
"\tpmsg %p\n",
pszHeader,
pQueryInfo,
pQueryInfo->Status, pQueryInfo->Status,
pQueryInfo->CharSet,
PRINT_STRING_WIDE_CHARSET( pQueryInfo->pName, pQueryInfo->CharSet ),
PRINT_STRING_ANSI_CHARSET( pQueryInfo->pName, pQueryInfo->CharSet ),
pQueryInfo->pReservedName,
pQueryInfo->Type,
pQueryInfo->Rcode,
pQueryInfo->Flags,
pQueryInfo->pAnswerRecords,
pQueryInfo->pAliasRecords,
pQueryInfo->pAuthorityRecords,
pQueryInfo->pAdditionalRecords,
//pQueryInfo->pSigRecords,
pQueryInfo->hEvent,
pQueryInfo->pDnsServers,
pQueryInfo->pMessage
);
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Answer records:\n",
pQueryInfo->pAnswerRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Alias records:\n",
pQueryInfo->pAliasRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Authority records:\n",
pQueryInfo->pAuthorityRecords );
DnsPrint_RecordSet(
PrintRoutine,
pContext,
"Additional records:\n",
pQueryInfo->pAdditionalRecords );
//DnsPrint_RecordSet(
// "Signature records:\n",
// pQueryInfo->pSigRecords );
DnsPrint_Unlock();
}
VOID
DnsPrint_EnvarInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PENVAR_DWORD_INFO pEnvar
)
/*++
Routine Description:
Print envar data
Arguments:
PrintRoutine - routine to print with
pContext - print context
pszHeader -- header to print with
pEnvar -- ptr to envar info
Return Value:
ERROR_SUCCESS if successful.
ErrorCode on failure.
--*/
{
PrintRoutine(
pContext,
"%s\n"
"\tId = %d\n"
"\tValue = %p\n"
"\tfFound = %d\n",
pszHeader ? pszHeader : "Envar Info:",
pEnvar->Id,
pEnvar->Value,
pEnvar->fFound
);
}
//
// Network info print routines.
//
VOID
DnsPrint_NetworkInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pPrintContext,
IN LPSTR pszHeader,
IN PDNS_NETINFO pNetworkInfo
)
/*++
Routine Description:
Prints and validates network info structure.
Should also touch all the memory and AV when bogus.
Arguments:
pNetworkInfo -- network info to print
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "NetworkInfo:";
}
if ( !pNetworkInfo )
{
PrintRoutine(
pPrintContext,
"%s NULL NetworkInfo.\n",
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pPrintContext,
"%s\n"
"\tpointer = %p\n"
"\tpszHostName = %s\n"
"\tpszDomainName = %s\n"
"\tpSearchList = %p\n"
"\tTimeStamp = %d\n"
"\tInfoFlags = %08x\n"
"\tReturnFlags = %08x\n"
"\tAdapterCount = %d\n"
"\tAdapterArraySize = %d\n",
pszHeader,
pNetworkInfo,
pNetworkInfo->pszHostName,
pNetworkInfo->pszDomainName,
pNetworkInfo->pSearchList,
pNetworkInfo->TimeStamp,
pNetworkInfo->InfoFlags,
pNetworkInfo->ReturnFlags,
pNetworkInfo->AdapterCount,
pNetworkInfo->MaxAdapterCount );
// print search list
DnsPrint_SearchList(
PrintRoutine,
pPrintContext,
"Search List: ",
pNetworkInfo->pSearchList );
// print server lists
for ( i=0; i < pNetworkInfo->AdapterCount; i++ )
{
CHAR header[60];
sprintf( header, "AdapterInfo[%d]:", i );
DnsPrint_AdapterInfo(
PrintRoutine,
pPrintContext,
header,
pNetworkInfo->AdapterArray[i] );
}
PrintRoutine(
pPrintContext,
"\n" );
DnsPrint_Unlock();
}
VOID
DnsPrint_AdapterInfo(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pPrintContext,
IN LPSTR pszHeader,
IN PDNS_ADAPTER pAdapter
)
/*++
Routine Description:
Prints and validates DNS adapter info.
Should also touch all the memory and AV when bogus.
Arguments:
pAdapter -- DNS adapter to print
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Adapter Info:";
}
if ( !pAdapter )
{
PrintRoutine(
pPrintContext,
"%s NULL Adapter info.\n",
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pPrintContext,
"%s\n"
"\tpointer = %p\n"
"\tDomain = %s\n"
"\tGuid Name = %s\n"
"\tInterfaceIndex = %d\n"
"\tInfoFlags = %08x\n"
"\tStatus = %d\n"
"\tRunFlags = %08x\n"
"\tServerIndex = %d\n"
"\tServerCount = %d\n"
"\tServerArraySize = %d\n",
pszHeader,
pAdapter,
pAdapter->pszAdapterDomain,
pAdapter->pszAdapterGuidName,
pAdapter->InterfaceIndex,
pAdapter->InfoFlags,
pAdapter->Status,
pAdapter->RunFlags,
pAdapter->ServerIndex,
pAdapter->ServerCount,
pAdapter->MaxServerCount );
// DNS server info
for ( i=0; i < pAdapter->ServerCount; i++ )
{
// DCR: IP6 DNS server address
PrintRoutine(
pPrintContext,
"\tDNS Server [%d]:\n"
"\t\tIpAddr = %s\n"
"\t\tPriority = %d\n"
"\t\tStatus = %d (%08x)\n",
i,
IP_STRING( pAdapter->ServerArray[i].IpAddress ),
pAdapter->ServerArray[i].Priority,
pAdapter->ServerArray[i].Status,
pAdapter->ServerArray[i].Status
);
}
// IP address info
DnsPrint_IpArray(
PrintRoutine,
pPrintContext,
"IP Addrs",
"IP",
pAdapter->pAdapterIPAddresses );
DnsPrint_IpArray(
PrintRoutine,
pPrintContext,
"IP Addr Subnets",
"Mask",
pAdapter->pAdapterIPSubnetMasks );
DnsPrint_Unlock();
}
VOID
DnsPrint_SearchList(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pPrintContext,
IN LPSTR pszHeader,
IN PSEARCH_LIST pSearchList
)
/*++
Routine Description:
Prints and validates DNS search list.
Should also touch all the memory and AV when bogus.
Arguments:
pSearchList -- search list to print
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "DNS Search List:";
}
if ( ! pSearchList )
{
PrintRoutine(
pPrintContext,
"%s NULL search list.\n",
pszHeader );
return;
}
DnsPrint_Lock();
PrintRoutine(
pPrintContext,
"%s\n"
"\tpointer = %p\n"
"\tpszDomain = %s\n"
"\tcNameCount = %d\n"
"\tcTotalListSize = %d\n"
"\tCurrentName = %d\n"
"\tSearchListNames:\n",
pszHeader,
pSearchList,
pSearchList->pszDomainOrZoneName,
pSearchList->NameCount,
pSearchList->MaxNameCount,
pSearchList->CurrentNameIndex
);
for ( i=0; i < pSearchList->NameCount; i++ )
{
PrintRoutine(
pPrintContext,
"\t\t%s (Flags: %08x)\n",
pSearchList->SearchNameArray[i].pszName,
pSearchList->SearchNameArray[i].Flags );
}
DnsPrint_Unlock();
}
VOID
DnsPrint_HostentBlob(
IN PRINT_ROUTINE PrintRoutine,
IN OUT PPRINT_CONTEXT pContext,
IN PSTR pszHeader,
IN PHOSTENT_BLOB pBlob
)
/*++
Routine Description:
Print hostent structure.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pBlob - ptr to hostent blob
Return Value:
None.
--*/
{
DWORD i;
if ( !pszHeader )
{
pszHeader = "Hostent Blob:";
}
if ( !pBlob )
{
PrintRoutine(
pContext,
"%s %s\r\n",
pszHeader,
"NULL Hostent blob ptr." );
return;
}
// print the struct
DnsPrint_Lock();
PrintRoutine(
pContext,
"%s\r\n"
"\tPtr = %p\n"
"\tpHostent = %p\n"
"\tfAllocatedBlob = %d\n"
"\tfAllocatedBuf = %d\n"
"\tpBuffer = %p\n"
"\tBufferLength = %d\n"
"\tAvailLength = %d\n"
"\tpAvailBuffer = %p\n"
"\tpCurrent = %p\n"
"\tBytesLeft = %d\n"
"\tMaxAliasCount = %d\n"
"\tAliasCount = %d\n"
"\tMaxAddrCount = %d\n"
"\tAddrCount = %d\n"
"\tfWroteName = %d\n"
"\tfUnicode = %d\n"
"\tCharSet = %d\n",
pszHeader,
pBlob,
pBlob->pHostent,
pBlob->fAllocatedBlob,
pBlob->fAllocatedBuf,
pBlob->pBuffer,
pBlob->BufferLength,
pBlob->AvailLength,
pBlob->pAvailBuffer,
pBlob->pCurrent,
pBlob->BytesLeft,
pBlob->MaxAliasCount,
pBlob->AliasCount,
pBlob->MaxAddrCount,
pBlob->AddrCount,
pBlob->fWroteName,
pBlob->fUnicode,
pBlob->CharSet
);
// print the hostent
if ( pBlob->pHostent )
{
DnsPrint_Hostent(
PrintRoutine,
pContext,
NULL,
pBlob->pHostent,
pBlob->fUnicode
);
}
DnsPrint_Unlock();
}
//
// End of print.c
//