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