|
|
/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
rconvert.c
Abstract:
Domain Name System (DNS) Server -- Admin Client Library
RPC record conversion routines. Convert records in RPC buffer to DNS_RECORD type.
Author:
Jim Gilroy (jamesg) April, 1997
Revision History:
--*/
#include "dnsclip.h"
#define IS_COMPLETE_NODE( pRpcNode ) \
(!!((pRpcNode)->dwFlags & DNS_RPC_NODE_FLAG_COMPLETE))
//
// Copy-convert string from RPC format (UTF8) into DNS_RECORD buffer
// - assume previously allocated required buffer
//
// Note: no difference between string and name conversion as we're
// going FROM UTF8
//
#define COPY_UTF8_STR_TO_BUFFER( buf, psz, len, charSet ) \
Dns_StringCopy( \ (buf), \ NULL, \ (psz), \ (len), \ DnsCharSetUtf8, \ (charSet) )
//
// RPC record to DNS_RECORD conversion routines
//
PDNS_RECORD ARpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read A record data from packet.
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord;
DNS_ASSERT( pRpcRR->wDataLength == sizeof( IP_ADDRESS ) );
precord = Dns_AllocateRecord( sizeof( IP_ADDRESS ) ); if ( !precord ) { return NULL; } precord->Data.A.IpAddress = pRpcRR->Data.A.ipAddress;
return precord; }
PDNS_RECORD PtrRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Process PTR compatible record from wire. Includes: NS, PTR, CNAME, MB, MR, MG, MD, MF
Arguments:
pRpcRR - message being read
CharSet - character set for resulting record
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; PDNS_RPC_NAME pname = &pRpcRR->Data.PTR.nameNode; WORD bufLength;
//
// PTR data is another domain name
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_PTR_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname->cchNameLength, CharSet );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// write hostname into buffer, immediately following PTR data struct
//
precord->Data.PTR.pNameHost = (PCHAR)&precord->Data + sizeof(DNS_PTR_DATA);
COPY_UTF8_STR_TO_BUFFER( precord->Data.PTR.pNameHost, pname->achName, pname->cchNameLength, CharSet );
return precord; }
PDNS_RECORD SoaRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read SOA record from wire.
Arguments:
pRR - ptr to record with RR set context
pRpcRR - message being read
pchData - ptr to RR data field
pchEnd - ptr to byte after data field
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; WORD bufLength; DWORD dwLength; PDNS_RPC_NAME pnamePrimary = &pRpcRR->Data.SOA.namePrimaryServer; PDNS_RPC_NAME pnameAdmin;
//
// verify names in SOA record
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pnamePrimary) ) { DNS_ASSERT( FALSE ); return NULL; } pnameAdmin = DNS_GET_NEXT_NAME(pnamePrimary); if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pnameAdmin) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_SOA_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pnamePrimary->cchNameLength, CharSet ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pnameAdmin->cchNameLength, CharSet );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy fixed fields
//
RtlCopyMemory( (PCHAR) & precord->Data.SOA.dwSerialNo, (PCHAR) & pRpcRR->Data.SOA.dwSerialNo, SIZEOF_SOA_FIXED_DATA );
//
// copy names into RR buffer
// - primary server immediately follows SOA data struct
// - responsible party follows primary server
//
precord->Data.SOA.pNamePrimaryServer = (PCHAR)&precord->Data + sizeof(DNS_SOA_DATA); dwLength = COPY_UTF8_STR_TO_BUFFER( precord->Data.SOA.pNamePrimaryServer, pnamePrimary->achName, (DWORD)pnamePrimary->cchNameLength, CharSet ); precord->Data.SOA.pNameAdministrator = precord->Data.SOA.pNamePrimaryServer + dwLength;
COPY_UTF8_STR_TO_BUFFER( precord->Data.SOA.pNameAdministrator, pnameAdmin->achName, (DWORD)pnameAdmin->cchNameLength, CharSet );
return precord; }
PDNS_RECORD TxtRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read TXT compatible record from wire. Includes: TXT, X25, HINFO, ISDN
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; DWORD bufLength = 0; DWORD length = 0; INT count = 0; PCHAR pch; PCHAR pchend; PCHAR pchbuffer; PCHAR * ppstring; PDNS_RPC_NAME pname = &pRpcRR->Data.TXT.stringData;
//
// determine required buffer length and allocate
// - allocate space for each string
// - and ptr for each string
//
pch = (PCHAR)&pRpcRR->Data.TXT; pchend = pch + pRpcRR->wDataLength;
while ( pch < pchend ) { length = (UCHAR) *pch++; pch += length; count++; bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( length, CharSet ); } if ( pch != pchend ) { DNS_PRINT(( "ERROR: Invalid RPCstring data\n" " pch = %p\n" " pchEnd = %p\n" " count = %d\n" " length = %d\n", pch, pchend, count, length )); SetLastError( ERROR_INVALID_DATA ); return NULL; }
// allocate
bufLength += (WORD) DNS_TEXT_RECORD_LENGTH(count); precord = Dns_AllocateRecord( (WORD)bufLength ); if ( !precord ) { return NULL; } precord->Data.TXT.dwStringCount = count;
//
// go back through list copying strings to buffer
// - ptrs to strings are saved to argv like data section
// ppstring walks through this section
// - first string written immediately following data section
// - each subsequent string immediately follows predecessor
// pchbuffer keeps ptr to position to write strings
//
pch = (PCHAR)&pRpcRR->Data.TXT; ppstring = precord->Data.TXT.pStringArray; pchbuffer = (PCHAR)ppstring + (count * sizeof(PCHAR));
while ( pch < pchend ) { length = (DWORD)((UCHAR) *pch++); *ppstring++ = pchbuffer;
pchbuffer += COPY_UTF8_STR_TO_BUFFER( pchbuffer, pch, length, CharSet ); pch += length; #if DBG
DNS_PRINT(( "Read text string %s\n", * (ppstring - 1) )); count--; #endif
} DNS_ASSERT( pch == pchend && count == 0 );
return precord; }
PDNS_RECORD MinfoRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read MINFO record from wire.
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; WORD bufLength; DWORD dwLength; PDNS_RPC_NAME pname1 = &pRpcRR->Data.MINFO.nameMailBox; PDNS_RPC_NAME pname2;
//
// verify names in MINFO record
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname1) ) { DNS_ASSERT( FALSE ); return NULL; } pname2 = DNS_GET_NEXT_NAME(pname1); if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname2) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = (WORD) ( sizeof( DNS_MINFO_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname1->cchNameLength, CharSet ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname2->cchNameLength, CharSet ) );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy names into RR buffer
// - mailbox immediately follows MINFO data struct
// - errors mailbox immediately follows primary server
//
precord->Data.MINFO.pNameMailbox = (PCHAR)&precord->Data + sizeof( DNS_MINFO_DATA );
dwLength = COPY_UTF8_STR_TO_BUFFER( precord->Data.MINFO.pNameMailbox, pname1->achName, (DWORD)pname1->cchNameLength, CharSet ); precord->Data.MINFO.pNameErrorsMailbox = precord->Data.MINFO.pNameMailbox + dwLength;
COPY_UTF8_STR_TO_BUFFER( precord->Data.MINFO.pNameErrorsMailbox, pname2->achName, (DWORD)pname2->cchNameLength, CharSet );
return precord; }
PDNS_RECORD MxRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read MX compatible record from wire. Includes: MX, RT, AFSDB
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; PDNS_RPC_NAME pname = &pRpcRR->Data.MX.nameExchange; WORD bufLength;
//
// MX exchange is another DNS name
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_MX_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname->cchNameLength, CharSet );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy preference
//
precord->Data.MX.wPreference = pRpcRR->Data.MX.wPreference;
//
// write hostname into buffer, immediately following MX struct
//
precord->Data.MX.pNameExchange = (PCHAR)&precord->Data + sizeof( DNS_MX_DATA );
COPY_UTF8_STR_TO_BUFFER( precord->Data.MX.pNameExchange, pname->achName, pname->cchNameLength, CharSet );
return precord; }
PDNS_RECORD FlatRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read memory copy compatible record from wire. Includes AAAA and WINS types.
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; WORD bufLength;
//
// determine required buffer length and allocate
//
bufLength = pRpcRR->wDataLength;
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy packet data to record
//
RtlCopyMemory( & precord->Data, (PCHAR) &pRpcRR->Data.A, bufLength );
return precord; }
PDNS_RECORD SrvRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read SRV record from wire.
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; PDNS_RPC_NAME pname = &pRpcRR->Data.SRV.nameTarget; WORD bufLength;
//
// SRV target host is another DNS name
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_SRV_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname->cchNameLength, CharSet );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy SRV fixed fields
//
precord->Data.SRV.wPriority = pRpcRR->Data.SRV.wPriority; precord->Data.SRV.wWeight = pRpcRR->Data.SRV.wWeight; precord->Data.SRV.wPort = pRpcRR->Data.SRV.wPort;
//
// write hostname into buffer, immediately following SRV struct
//
precord->Data.SRV.pNameTarget = (PCHAR)&precord->Data + sizeof( DNS_SRV_DATA );
COPY_UTF8_STR_TO_BUFFER( precord->Data.SRV.pNameTarget, pname->achName, pname->cchNameLength, CharSet );
return precord; }
PDNS_RECORD NbstatRpcRecordConvert( IN PDNS_RPC_RECORD pRpcRR, IN DNS_CHARSET CharSet ) /*++
Routine Description:
Read WINSR record from wire.
Arguments:
pRpcRR - message being read
Return Value:
Ptr to new record if successful. NULL on failure.
--*/ { PDNS_RECORD precord; PDNS_RPC_NAME pname = &pRpcRR->Data.WINSR.nameResultDomain; WORD bufLength;
//
// WINSR target host is another DNS name
//
if ( ! DNS_IS_NAME_IN_RECORD(pRpcRR, pname) ) { DNS_ASSERT( FALSE ); return NULL; }
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_WINSR_DATA ) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname->cchNameLength, CharSet );
precord = Dns_AllocateRecord( bufLength ); if ( !precord ) { return NULL; }
//
// copy WINSR fixed fields
//
precord->Data.WINSR.dwMappingFlag = pRpcRR->Data.WINSR.dwMappingFlag; precord->Data.WINSR.dwLookupTimeout = pRpcRR->Data.WINSR.dwLookupTimeout; precord->Data.WINSR.dwCacheTimeout = pRpcRR->Data.WINSR.dwCacheTimeout;
//
// write hostname into buffer, immediately following WINSR struct
//
precord->Data.WINSR.pNameResultDomain = (PCHAR)&precord->Data + sizeof( DNS_WINSR_DATA ); COPY_UTF8_STR_TO_BUFFER( precord->Data.WINSR.pNameResultDomain, pname->achName, pname->cchNameLength, CharSet );
return precord; }
//
// RR conversion from RPC buffer to DNS_RECORD
//
typedef PDNS_RECORD (* RR_CONVERT_FUNCTION)( PDNS_RPC_RECORD, DNS_CHARSET );
RR_CONVERT_FUNCTION RRRpcConvertTable[] = { NULL, // ZERO
ARpcRecordConvert, // A
PtrRpcRecordConvert, // NS
PtrRpcRecordConvert, // MD
PtrRpcRecordConvert, // MF
PtrRpcRecordConvert, // CNAME
SoaRpcRecordConvert, // SOA
PtrRpcRecordConvert, // MB
PtrRpcRecordConvert, // MG
PtrRpcRecordConvert, // MR
NULL, // NULL
FlatRpcRecordConvert, // WKS
PtrRpcRecordConvert, // PTR
TxtRpcRecordConvert, // HINFO
MinfoRpcRecordConvert, // MINFO
MxRpcRecordConvert, // MX
TxtRpcRecordConvert, // TXT
MinfoRpcRecordConvert, // RP
MxRpcRecordConvert, // AFSDB
TxtRpcRecordConvert, // X25
TxtRpcRecordConvert, // ISDN
MxRpcRecordConvert, // RT
NULL, // NSAP
NULL, // NSAPPTR
NULL, // SIG
NULL, // KEY
NULL, // PX
NULL, // GPOS
FlatRpcRecordConvert, // AAAA
NULL, // 29
NULL, // 30
NULL, // 31
NULL, // 32
SrvRpcRecordConvert, // SRV
NULL, // ATMA
NULL, // 35
NULL, // 36
NULL, // 37
NULL, // 38
NULL, // 39
NULL, // 40
NULL, // OPT
NULL, // 42
NULL, // 43
NULL, // 44
NULL, // 45
NULL, // 46
NULL, // 47
NULL, // 48
//
// NOTE: last type indexed by type ID MUST be set
// as MAX_SELF_INDEXED_TYPE #define in record.h
// (see note above in record info table)
// note these follow, but require OFFSET_TO_WINS_RR subtraction
// from actual type value
NULL, // TKEY
NULL, // TSIG
FlatRpcRecordConvert, // WINS
NbstatRpcRecordConvert // WINS-R
};
//
// API for doing conversion
//
PDNS_RECORD DnsConvertRpcBufferToRecords( IN PBYTE * ppByte, IN PBYTE pStopByte, IN DWORD cRecords, IN PDNS_NAME pszNodeName, IN BOOLEAN fUnicode ) /*++
Routine Description:
Convert RPC buffer records to standard DNS records.
Arguments:
ppByte -- addr of ptr into buffer where records start
pStopByte -- stop byte of buffer
cRecords -- number of records to convert
pszNodeName -- node name (in desired format, not converted)
fUnicode -- flag, write records into unicode
Return Value:
Ptr to new record(s) if successful. NULL on failure.
--*/ { PDNS_RPC_RECORD prpcRecord = (PDNS_RPC_RECORD)*ppByte; PDNS_RECORD precord; DNS_RRSET rrset; WORD index; WORD type; DNS_CHARSET charSet; RR_CONVERT_FUNCTION pFunc;
DNS_ASSERT( DNS_IS_DWORD_ALIGNED(prpcRecord) ); IF_DNSDBG( RPC2 ) { DNS_PRINT(( "Enter DnsConvertRpcBufferToRecords()\n" " pRpcRecord = %p\n" " Count = %d\n" " Nodename = %s%S\n", prpcRecord, cRecords, DNSSTRING_UTF8( fUnicode, pszNodeName ), DNSSTRING_WIDE( fUnicode, pszNodeName ) )); }
DNS_RRSET_INIT( rrset );
//
// loop until out of nodes
//
while( cRecords-- ) { if ( (PBYTE)prpcRecord >= pStopByte || (PBYTE)&prpcRecord->Data + prpcRecord->wDataLength > pStopByte ) { DNS_PRINT(( "ERROR: Bogus buffer at %p\n" " Record leads past buffer end at %p\n" " with %d records remaining\n", prpcRecord, pStopByte, cRecords+1 )); DNS_ASSERT( FALSE ); return NULL; }
//
// convert record
// set unicode flag if converting
//
charSet = DnsCharSetUtf8; if ( fUnicode ) { charSet = DnsCharSetUnicode; }
type = prpcRecord->wType; index = INDEX_FOR_TYPE( type ); DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
if ( !index || !(pFunc = RRRpcConvertTable[ index ]) ) { // if unknown type try flat record copy -- best we can
// do to protect if server added new types since admin built
DNS_PRINT(( "ERROR: no RPC to DNS_RECORD conversion routine for type %d\n" " using flat conversion routine\n", type )); pFunc = FlatRpcRecordConvert; }
precord = (*pFunc)( prpcRecord, charSet ); if ( ! precord ) { DNS_PRINT(( "ERROR: Record build routine failure for record type %d\n" " status = %p\n\n", type, GetLastError() ));
prpcRecord = DNS_GET_NEXT_RPC_RECORD(prpcRecord); continue; }
//
// fill out record structure
//
precord->pName = pszNodeName; precord->wType = type; RECORD_CHARSET( precord ) = charSet;
//
// DEVNOTE: data types (root hint, glue set)
//
if ( prpcRecord->dwFlags & DNS_RPC_RECORD_FLAG_CACHE_DATA ) { precord->Flags.S.Section = DNSREC_CACHE_DATA; } else { precord->Flags.S.Section = DNSREC_ZONE_DATA; }
IF_DNSDBG( INIT ) { DnsDbg_Record( "New record built\n", precord ); }
//
// link into RR set
//
DNS_RRSET_ADD( rrset, precord );
prpcRecord = DNS_GET_NEXT_RPC_RECORD(prpcRecord); }
IF_DNSDBG( RPC2 ) { DnsDbg_RecordSet( "Finished DnsConvertRpcBufferToRecords() ", rrset.pFirstRR ); }
// reset ptr in buffer
*ppByte = (PBYTE) prpcRecord;
return rrset.pFirstRR; }
PDNS_NODE DnsConvertRpcBufferNode( IN PDNS_RPC_NODE pRpcNode, IN PBYTE pStopByte, IN BOOLEAN fUnicode ) /*++
Routine Description:
Convert RPC buffer records to standard DNS records.
Arguments:
pRpcNode -- ptr to RPC node in buffer
pStopByte -- stop byte of buffer
fUnicode -- flag, write records into unicode
Return Value:
Ptr to new node if successful. NULL on failure.
--*/ { PDNS_NODE pnode; PDNS_RPC_NAME pname; PBYTE pendNode;
IF_DNSDBG( RPC2 ) { DnsDbg_RpcNode( "Enter DnsConvertRpcBufferNode() ", pRpcNode ); }
//
// validate node
//
DNS_ASSERT( DNS_IS_DWORD_ALIGNED(pRpcNode) ); pendNode = (PBYTE)pRpcNode + pRpcNode->wLength; if ( pendNode > pStopByte ) { DNS_ASSERT( FALSE ); return NULL; } pname = &pRpcNode->dnsNodeName; if ( (PBYTE)DNS_GET_NEXT_NAME(pname) > pendNode ) { DNS_ASSERT( FALSE ); return NULL; }
//
// create node
//
pnode = (PDNS_NODE) ALLOCATE_HEAP( sizeof(DNS_NODE) + STR_BUF_SIZE_GIVEN_UTF8_LEN( pname->cchNameLength, fUnicode ) ); if ( !pnode ) { return NULL; } pnode->pNext = NULL; pnode->pRecord = NULL; pnode->Flags.W = 0;
//
// copy owner name, starts directly after node structure
//
pnode->pName = (PWCHAR) ((PBYTE)pnode + sizeof(DNS_NODE));
if ( ! Dns_StringCopy( (PCHAR) pnode->pName, NULL, pname->achName, pname->cchNameLength, DnsCharSetUtf8, // UTF8 in
fUnicode ? DnsCharSetUnicode : DnsCharSetUtf8 ) ) { // name conversion error
DNS_ASSERT( FALSE ); FREE_HEAP( pnode ); return NULL; } IF_DNSDBG( RPC2 ) { DnsDbg_RpcName( "Node name in RPC buffer: ", pname, "\n" ); DnsDbg_String( "Converted name ", (PCHAR) pnode->pName, fUnicode, "\n" ); }
//
// set flags
// - name always internal
// - catch domain roots
//
pnode->Flags.S.Unicode = fUnicode;
if ( pRpcNode->dwChildCount || (pRpcNode->dwFlags & DNS_RPC_NODE_FLAG_STICKY) ) { pnode->Flags.S.Domain = TRUE; }
IF_DNSDBG( RPC2 ) { DnsDbg_Node( "Finished DnsConvertRpcBufferNode() ", pnode, TRUE ); // view the records
} return pnode; }
PDNS_NODE DnsConvertRpcBuffer( OUT PDNS_NODE * ppNodeLast, IN DWORD dwBufferLength, IN BYTE abBuffer[], IN BOOLEAN fUnicode ) { PBYTE pbyte; PBYTE pstopByte; INT countRecords; PDNS_NODE pnode; PDNS_NODE pnodeFirst = NULL; PDNS_NODE pnodeLast = NULL; PDNS_RECORD precord;
IF_DNSDBG( RPC2 ) { DNS_PRINT(( "DnsConvertRpcBuffer( %p ), len = %d\n", abBuffer, dwBufferLength )); }
//
// find stop byte
//
DNS_ASSERT( DNS_IS_DWORD_ALIGNED(abBuffer) );
pstopByte = abBuffer + dwBufferLength; pbyte = abBuffer;
//
// loop until out of nodes
//
while( pbyte < pstopByte ) { //
// build owner node
// - only build complete nodes
// - add to list
//
if ( !IS_COMPLETE_NODE( (PDNS_RPC_NODE)pbyte ) ) { break; } pnode = DnsConvertRpcBufferNode( (PDNS_RPC_NODE)pbyte, pstopByte, fUnicode ); if ( !pnode ) { DNS_ASSERT( FALSE ); // DEVNOTE: cleanup
return NULL; } if ( !pnodeFirst ) { pnodeFirst = pnode; pnodeLast = pnode; } else { pnodeLast->pNext = pnode; pnodeLast = pnode; }
countRecords = ((PDNS_RPC_NODE)pbyte)->wRecordCount; pbyte += ((PDNS_RPC_NODE)pbyte)->wLength; pbyte = DNS_NEXT_DWORD_PTR(pbyte);
//
// for each node, build all records
//
if ( countRecords ) { precord = DnsConvertRpcBufferToRecords( & pbyte, pstopByte, countRecords, (PCHAR) pnode->pName, fUnicode ); if ( !precord ) { DNS_ASSERT( FALSE ); } pnode->pRecord = precord; } }
// set last node and return first node
*ppNodeLast = pnodeLast;
return pnodeFirst; }
//
// End rconvert.c
//
|