Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1802 lines
42 KiB

/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
rrread.c
Abstract:
Domain Name System (DNS) Library
Read resource record from packet routines.
Author:
Jim Gilroy (jamesg) January, 1997
Revision History:
--*/
#include "local.h"
PDNS_RECORD
A_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read A record data from packet.
Arguments:
pRR - RR context
pchStart - start of DNS message
pchData - ptr to packet RR data
wLength - length of RR data in packet
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
if ( pchEnd - pchData != sizeof(IP4_ADDRESS) )
{
SetLastError( ERROR_INVALID_DATA );
return( NULL );
}
precord = Dns_AllocateRecord( sizeof(IP4_ADDRESS) );
if ( !precord )
{
return( NULL );
}
precord->Data.A.IpAddress = *(UNALIGNED DWORD *) pchData;
return( precord );
}
PDNS_RECORD
Ptr_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Process PTR compatible record from wire.
Includes: NS, PTR, CNAME, MB, MR, MG, MD, MF
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
WORD nameLength;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// PTR data is another domain name
//
pchData = Dns_ReadPacketName(
nameBuffer,
& nameLength,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( pchData != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_PTR_DATA );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
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 );
Dns_NameCopy(
precord->Data.PTR.pNameHost,
NULL, // no buffer length
nameBuffer,
nameLength,
DnsCharSetWire,
OutCharSet
);
return( precord );
}
PDNS_RECORD
Soa_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read SOA record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
PCHAR pchendFixed;
PDWORD pdword;
WORD nameLength1;
WORD nameLength2;
CHAR nameBuffer1[ DNS_MAX_NAME_BUFFER_LENGTH ];
CHAR nameBuffer2[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// read DNS names
//
pchData = Dns_ReadPacketName(
nameBuffer1,
& nameLength1,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( !pchData || pchData >= pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
pchData = Dns_ReadPacketName(
nameBuffer2,
& nameLength2,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
pchendFixed = pchData + SIZEOF_SOA_FIXED_DATA;
if ( pchendFixed != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_SOA_DATA );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength1, OutCharSet );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength2, OutCharSet );
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy fixed fields
//
pdword = &precord->Data.SOA.dwSerialNo;
while ( pchData < pchendFixed )
{
*pdword++ = FlipUnalignedDword( pchData );
pchData += sizeof(DWORD);
}
//
// 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);
precord->Data.SOA.pNameAdministrator =
precord->Data.SOA.pNamePrimaryServer +
Dns_NameCopy(
precord->Data.SOA.pNamePrimaryServer,
NULL, // no buffer length
nameBuffer1,
nameLength1,
DnsCharSetWire,
OutCharSet );
Dns_NameCopy(
precord->Data.SOA.pNameAdministrator,
NULL, // no buffer length
nameBuffer2,
nameLength2,
DnsCharSetWire,
OutCharSet
);
return( precord );
}
PDNS_RECORD
Txt_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read TXT compatible record from wire.
Includes: TXT, X25, HINFO, ISDN
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
WORD length;
INT count;
PCHAR pch;
PCHAR pchbuffer;
PCHAR * ppstring;
//
// determine required buffer length and allocate
// - allocate space for each string
// - and ptr for each string
//
bufLength = 0;
count = 0;
pch = pchData;
while ( pch < pchEnd )
{
length = (UCHAR) *pch++;
pch += length;
count++;
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( length, OutCharSet );
}
if ( pch != pchEnd )
{
DNS_PRINT((
"ERROR: Invalid packet string data.\n"
"\tpch = %p\n"
"\tpchEnd = %p\n"
"\tcount = %d\n"
"\tlength = %d\n",
pch, pchEnd, count, length
));
SetLastError( ERROR_INVALID_DATA );
return( NULL );
}
// allocate
bufLength += (WORD) DNS_TEXT_RECORD_LENGTH(count);
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
precord->Data.TXT.dwStringCount = count;
//
// DCR: if separate HINFO type -- handle this here
// - set pointer differently
// - validate string count found
//
//
// 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 = pchData;
ppstring = (PCHAR *) precord->Data.TXT.pStringArray;
pchbuffer = (PBYTE)ppstring + (count * sizeof(PCHAR));
while ( pch < pchEnd )
{
length = (UCHAR) *pch++;
#if DBG
DNS_PRINT((
"Reading text at %p (len %d), to buffer at %p\n"
"\tsave text ptr[%d] at %p in precord (%p)\n",
pch,
length,
pchbuffer,
(PCHAR *) ppstring - (PCHAR *) precord->Data.TXT.pStringArray,
ppstring,
precord ));
#endif
*ppstring++ = pchbuffer;
pchbuffer += Dns_StringCopy(
pchbuffer,
NULL,
pch,
length,
DnsCharSetWire,
OutCharSet );
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
Minfo_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read MINFO record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
WORD nameLength1;
WORD nameLength2;
CHAR nameBuffer1[ DNS_MAX_NAME_BUFFER_LENGTH ];
CHAR nameBuffer2[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// read DNS names
//
pchData = Dns_ReadPacketName(
nameBuffer1,
& nameLength1,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( !pchData || pchData >= pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
pchData = Dns_ReadPacketName(
nameBuffer2,
& nameLength2,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( pchData != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_MINFO_DATA );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength1, OutCharSet );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength2, OutCharSet );
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy names into RR buffer
// - primary server immediately follows MINFO data struct
// - responsible party follows primary server
//
precord->Data.MINFO.pNameMailbox =
(PCHAR)&precord->Data + sizeof( DNS_MINFO_DATA );
precord->Data.MINFO.pNameErrorsMailbox =
precord->Data.MINFO.pNameMailbox +
Dns_NameCopy(
precord->Data.MINFO.pNameMailbox,
NULL, // no buffer length
nameBuffer1,
nameLength1,
DnsCharSetWire,
OutCharSet );
Dns_NameCopy(
precord->Data.MINFO.pNameErrorsMailbox,
NULL, // no buffer length
nameBuffer2,
nameLength2,
DnsCharSetWire,
OutCharSet
);
return( precord );
}
PDNS_RECORD
Mx_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read MX compatible record from wire.
Includes: MX, RT, AFSDB
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
WORD nameLength;
WORD wpreference;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
// read preference value
wpreference = FlipUnalignedWord( pchData );
pchData += sizeof(WORD);
// read mail exchange
pchData = Dns_ReadPacketName(
nameBuffer,
& nameLength,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( pchData != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_MX_DATA );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
// copy preference
precord->Data.MX.wPreference = wpreference;
//
// write exchange name into buffer, immediately following MX data struct
//
precord->Data.MX.pNameExchange = (PCHAR)&precord->Data + sizeof( DNS_MX_DATA );
Dns_NameCopy(
precord->Data.MX.pNameExchange,
NULL, // no buffer length
nameBuffer,
nameLength,
DnsCharSetWire,
OutCharSet
);
return( precord );
}
PDNS_RECORD
Flat_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read memory copy compatible record from wire.
Includes AAAA type.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
//
// determine required buffer length and allocate
//
bufLength = (WORD)(pchEnd - pchData);
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy packet data to record
//
memcpy(
& precord->Data,
pchData,
bufLength );
return( precord );
}
PDNS_RECORD
Srv_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read SRV record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
WORD nameLength;
PCHAR pchstart;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// read SRV target name
// - name is after fixed length integer data
pchstart = pchData;
pchData += SIZEOF_SRV_FIXED_DATA;
pchData = Dns_ReadPacketName(
nameBuffer,
& nameLength,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( pchData != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof( DNS_SRV_DATA );
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy integer fields
//
precord->Data.SRV.wPriority = FlipUnalignedWord( pchstart );
pchstart += sizeof( WORD );
precord->Data.SRV.wWeight = FlipUnalignedWord( pchstart );
pchstart += sizeof( WORD );
precord->Data.SRV.wPort = FlipUnalignedWord( pchstart );
//
// copy target host name into RR buffer
// - write target host immediately following SRV data struct
//
precord->Data.SRV.pNameTarget = (PCHAR)&precord->Data + sizeof( DNS_SRV_DATA );
Dns_NameCopy(
precord->Data.SRV.pNameTarget,
NULL, // no buffer length
nameBuffer,
nameLength,
DnsCharSetWire,
OutCharSet
);
return( precord );
}
PDNS_RECORD
Atma_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read ATMA record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
PCHAR pchstart;
WORD wLen = (WORD) (pchEnd - pchData);
pchstart = pchData;
precord = Dns_AllocateRecord( sizeof( DNS_ATMA_DATA ) +
DNS_ATMA_MAX_ADDR_LENGTH );
if ( !precord )
{
return( NULL );
}
//
// copy ATMA integer fields
//
precord->Data.ATMA.AddressType = *pchstart;
pchstart += sizeof( BYTE );
if ( precord->Data.ATMA.AddressType == DNS_ATMA_FORMAT_E164 )
{
precord->wDataLength = wLen;
if ( precord->wDataLength > DNS_ATMA_MAX_ADDR_LENGTH )
precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
}
else
{
precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
}
//
// copy ATMA address field
//
memcpy( (PCHAR)&precord->Data.ATMA.Address,
pchstart,
precord->wDataLength - sizeof( BYTE ) );
return( precord );
}
PDNS_RECORD
Wks_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read Wks record data from packet.
Arguments:
pRR - RR context
pchStart - start of DNS message
pchData - ptr to packet RR data field
pchEnd - ptr to end of the data field
Return Value:
Ptr to new record if successful.
NULL on failure.
Author:
Cameron Etezadi (camerone) - 1 May 1997
- for NS Lookup purposes, must add this function
NOTE:
NONE of the getXXXbyYYY calls return unicode in their
structures! If we want the returned record to be unicode,
then we must translate. I am leaving it as char* for now,
can go back later and fix this.
--*/
{
PDNS_RECORD pRecord;
WORD wLength;
PCHAR pStart;
UCHAR cProto;
struct protoent * proto;
struct servent * serv;
IP4_ADDRESS ipAddress;
char * szListOfServices;
int nSize;
char * szProtoName;
BYTE cMask = 0x80; // is this right? Left to right?
BYTE cByteToCheck;
int i;
int j = 0;
int nPortNumToQuery;
int nCurLength = 1;
char * szTemp;
pStart = pchData;
if (! pStart)
{
DNS_PRINT(( "ERROR: WKS did not get a record.\n" ));
SetLastError( ERROR_INVALID_DATA );
return(NULL);
}
//
// Check size. Must at least be an IP Address + a protocol
//
if ((pchEnd - pchData) < (sizeof(IP4_ADDRESS) + sizeof(UCHAR)))
{
DNS_PRINT(( "ERROR: WKS packet was too small for any data.\n" ));
SetLastError( ERROR_INVALID_DATA );
return(NULL);
}
//
// Fill in the ip and protocol
//
ipAddress = *(UNALIGNED DWORD *)pStart;
pStart += sizeof(IP4_ADDRESS);
cProto = *(UCHAR *)pStart;
pStart += sizeof(UCHAR);
//
// Redefined the WKS structure to contain a listing
// of space separated monikers for the services
//
// Get the protocol
//
proto = getprotobynumber(cProto);
if (!proto)
{
DNS_PRINT(( "ERROR: WKS failed to resolve protocol number to name.\n" ));
SetLastError(ERROR_INVALID_DATA);
return(NULL);
}
nSize = strlen(proto->p_name);
szProtoName = ALLOCATE_HEAP((nSize + 1) * sizeof(char));
if (!szProtoName)
{
DNS_PRINT(( "ERROR: WKS could not allocate space for proto name\n"));
SetLastError(ERROR_OUTOFMEMORY);
return(NULL);
}
strcpy(szProtoName, proto->p_name);
//
// Now, the tricky part. This is a bitmask.
// I must translate to a string for each bit marked in the bitmask
//
DNS_PRINT(( "Now checking bitmask bits.\n"));
szTemp = NULL;
szListOfServices = ALLOCATE_HEAP(sizeof(char));
if (!szListOfServices)
{
DNS_PRINT(( "ERROR: WKS could not allocate space for services name\n"));
SetLastError(ERROR_OUTOFMEMORY);
FREE_HEAP(szProtoName);
return(NULL);
}
else
{
*szListOfServices = '\0';
}
while (pStart < pchEnd)
{
cByteToCheck = *(BYTE *)pStart;
for (i = 0; i < 8; i++)
{
if (cByteToCheck & cMask)
{
// This is a service that is valid
nPortNumToQuery = i + (8 * j);
serv = getservbyport(htons((USHORT)nPortNumToQuery), szProtoName);
if (! serv)
{
DNS_PRINT(( "ERROR: WKS found a port that could not be translated\n"));
SetLastError(ERROR_INVALID_DATA);
FREE_HEAP(szProtoName);
FREE_HEAP(szListOfServices);
return(NULL);
}
nSize = strlen(serv->s_name);
nCurLength = nCurLength + nSize + 1;
//
// Allocate more memory. We need the + 1 here
// because we will overwrite the existing null with a strcat
// (removing the need) but use a space to separate items
//
szTemp = ALLOCATE_HEAP( nCurLength);
if (! szTemp)
{
DNS_PRINT(( "ERROR: WKS alloc space for services name\n" ));
SetLastError(ERROR_OUTOFMEMORY);
FREE_HEAP(szProtoName);
FREE_HEAP(szListOfServices);
return(NULL);
}
else
{
strcpy( szTemp, szListOfServices );
FREE_HEAP( szListOfServices );
szListOfServices = szTemp;
szTemp = NULL;
}
//
// Append the retrieved service name to the end of the list
//
strcat(szListOfServices, serv->s_name);
strcat(szListOfServices, " ");
}
cByteToCheck <<= 1;
}
//
// Increment the "how many bytes have we done" offset counter
//
j++;
pStart += sizeof(BYTE);
}
FREE_HEAP(szProtoName);
//
// Allocate a record and fill it in.
//
wLength = (WORD)(sizeof(IP4_ADDRESS) + sizeof(UCHAR) + sizeof(int)
+ (sizeof(char) * ++nCurLength));
pRecord = Dns_AllocateRecord(wLength);
if ( !pRecord )
{
DNS_PRINT(( "ERROR: WKS failed to allocate record\n" ));
SetLastError(ERROR_OUTOFMEMORY);
FREE_HEAP(szListOfServices);
return(NULL);
}
pRecord->Data.WKS.IpAddress = ipAddress;
pRecord->Data.WKS.chProtocol = cProto;
strcpy((char *)pRecord->Data.WKS.BitMask, szListOfServices);
FREE_HEAP(szListOfServices);
return(pRecord);
}
PDNS_RECORD
Tkey_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
{
PCHAR pch;
PDNS_RECORD prr;
WORD bufLength;
WORD keyLength;
PCHAR pchstart;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// allocate record
//
bufLength = sizeof( DNS_TKEY_DATA );
prr = Dns_AllocateRecord( bufLength );
if ( !prr )
{
return( NULL );
}
prr->wType = DNS_TYPE_TKEY;
//
// algorithm name
//
pch = Dns_SkipPacketName(
pchData,
pchEnd );
if ( !pch )
{
goto Formerr;
}
prr->Data.TKEY.pAlgorithmPacket = (PDNS_NAME) pchData;
prr->Data.TKEY.cAlgNameLength = (UCHAR)(pch - pchData);
prr->Data.TKEY.pNameAlgorithm = NULL;
#if 0
//
// DEVNOTE: currently not allocating data for TKEY, using internal pointers
//
// allocated version
// note for this we won't have compression pointer which is fine
// since no name compression in data
// however function may need dummy to do the right thing
// should perhaps just pass in pchStart which can be dummy to
// real header
//
pch = Dns_ReadPacketNameAllocate(
& prr->Data.TKEY.pNameAlgorithm,
& nameLength,
NULL, // no previous name
NULL, // no previous name
pchData,
//pchStart, // have no packet context
NULL,
pchEnd );
if ( !pch )
{
DNSDBG( SECURITY, (
"WARNING: invalid TKEY algorithm name at %p.\n",
pch ));
goto Formerr;
}
#endif
//
// read fixed fields
//
if ( pch + SIZEOF_TKEY_FIXED_DATA >= pchEnd )
{
goto Formerr;
}
prr->Data.TKEY.dwCreateTime = InlineFlipUnalignedDword( pch );
pch += sizeof(DWORD);
prr->Data.TKEY.dwExpireTime = InlineFlipUnalignedDword( pch );
pch += sizeof(DWORD);
prr->Data.TKEY.wMode = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
prr->Data.TKEY.wError = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
prr->Data.TKEY.wKeyLength = keyLength = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
// now have key and other length to read
if ( pch + keyLength + sizeof(WORD) > pchEnd )
{
goto Formerr;
}
//
// save ptr to key
//
prr->Data.TKEY.pKey = pch;
pch += keyLength;
#if 0
//
// copy key
//
pkey = ALLOCATE_HEAP( keyLength );
if ( !pkey )
{
status = DNS_ERROR_NO_MEMORY;
goto Failed;
}
RtlCopyMemory(
pkey,
pch,
keyLength );
pch += keyLength;
#endif
//
// other data
//
prr->Data.TKEY.wOtherLength = keyLength = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
if ( pch + keyLength > pchEnd )
{
goto Formerr;
}
if ( !keyLength )
{
prr->Data.TKEY.pOtherData = NULL;
}
else
{
prr->Data.TKEY.pOtherData = pch;
}
// DCR_ENHANCE: TKEY end-of-data verification
// returning TKEY with packet pointers as only point is processing
prr->Data.TKEY.bPacketPointers = TRUE;
//
// DCR_ENHANCE: copied subfields, best to get here with stack record, then
// allocate RR containing subfields and copy everything
return( prr );
Formerr:
DNSDBG( ANY, (
"ERROR: FOMERR processing TKEY at %p in message\n",
pchData ));
// free record
// if switch to allocated subfields need
FREE_HEAP( prr );
return( NULL );
}
PDNS_RECORD
Tsig_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read SRV record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - [OLD SEMANTICS, UNUSED] start of DNS message
OVERLOAD pchStart!!
Since we're stuck w/ this function signature, we'll overload
the unused param pchStart to get the iKeyVersion.
pchData - ptr to RR data field
pchEnd - ptr to byte after data field
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PCHAR pch;
PDNS_RECORD prr;
WORD bufLength;
WORD sigLength;
PCHAR pchstart;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
#if 0
// currently do not need versioning info
// if had to do again, should extract version then pass
// in another pRR field; or send entire packet context
//
// extract current TSIG version (from key string)
//
ASSERT( pRR );
iKeyVersion = Dns_GetKeyVersion( pRR->pName );
#endif
//
// allocate record
//
bufLength = sizeof( DNS_TSIG_DATA );
prr = Dns_AllocateRecord( bufLength );
if ( !prr )
{
return( NULL );
}
prr->wType = DNS_TYPE_TSIG;
//
// algorithm name
//
pch = Dns_SkipPacketName(
pchData,
pchEnd );
if ( !pch )
{
DNSDBG( SECURITY, (
"WARNING: invalid TSIG RR algorithm name.\n" ));
goto Formerr;
}
prr->Data.TSIG.pAlgorithmPacket = (PDNS_NAME) pchData;
prr->Data.TSIG.cAlgNameLength = (UCHAR)(pch - pchData);
#if 0
// allocated version
// note for this we won't have compression pointer which is fine
// since no name compression in data
// however function may need dummy to do the right thing
// should perhaps just pass in pchStart which can be dummy
// to real header
//
pch = Dns_ReadPacketNameAllocate(
& prr->Data.TSIG.pNameAlgorithm,
& nameLength,
NULL, // no previous name
NULL, // no previous name
pchData,
//pchStart, // have no packet context
NULL,
pchEnd );
if ( !pch )
{
DNSDBG( SECURITY, (
"WARNING: invalid TSIG RR algorithm name at %p.\n",
pch ));
goto Formerr;
}
#endif
//
// read fixed fields
//
if ( pch + SIZEOF_TSIG_FIXED_DATA >= pchEnd )
{
DNSDBG( SECURITY, (
"ERROR: TSIG has inadequate length for fixed fields.\n" ));
goto Formerr;
}
//
// read time fields
// - 48 bit create time
// - 16 bit fudge
//
prr->Data.TSIG.i64CreateTime = InlineFlipUnaligned48Bits( pch );
pch += sizeof(DWORD) + sizeof(WORD);
prr->Data.TSIG.wFudgeTime = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
//
// save sig length and sig pointer
//
prr->Data.TSIG.wSigLength = sigLength = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
prr->Data.TSIG.pSignature = pch;
pch += sigLength;
//
// verify rest of fields within packet
// - signature
// - original XID
// - extended RCODE
// - other data length field
// - other data
//
if ( pch + SIZEOF_TSIG_POST_SIG_FIXED_DATA > pchEnd )
{
DNSDBG( SECURITY, (
"ERROR: TSIG has inadequate length for post-sig fixed fields.\n" ));
goto Formerr;
}
#if 0
//
// note: if this activated, would need to validate length pull
// sig ptr thing above and change validation to include sig length
//
// copy sig
//
psig = ALLOCATE_HEAP( sigLength );
if ( !psig )
{
status = DNS_ERROR_NO_MEMORY;
goto Failed;
}
RtlCopyMemory(
psig,
pch,
sigLength );
pch += sigLength;
#endif
// original XID
// - leave in net order, as just replace in message for signing
prr->Data.TSIG.wOriginalXid = READ_PACKET_NET_WORD( pch );
pch += sizeof(WORD);
DNSDBG( SECURITY, (
"Read original XID <== 0x%x.\n",
prr->Data.TSIG.wOriginalXid ));
// error field
prr->Data.TSIG.wError = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
//
// other data
//
prr->Data.TSIG.wOtherLength = sigLength = InlineFlipUnalignedWord( pch );
pch += sizeof(WORD);
if ( pch + sigLength > pchEnd )
{
DNSDBG( SECURITY, (
"WARNING: invalid TSIG RR sigLength %p.\n",
pch ));
goto Formerr;
}
if ( !sigLength )
{
prr->Data.TSIG.pOtherData = NULL;
}
else
{
prr->Data.TSIG.pOtherData = pch;
}
// DCR_ENHANCE: TSIG end-of-data verification
// returning TSIG with packet pointers as only point is processing
prr->Data.TSIG.bPacketPointers = TRUE;
//
// DCR_ENHANCE: copied subfields, best to get here with stack record, then
// allocate RR containing subfields and copy everything
return( prr );
Formerr:
DNSDBG( ANY, (
"ERROR: FOMERR processing TSIG in message at %p\n" ));
// free record
// if switch to allocated subfields need
FREE_HEAP( prr );
return( NULL );
}
PDNS_RECORD
Wins_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read WINS record from wire.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
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;
//
// determine required buffer length and allocate
//
bufLength = (WORD)(pchEnd - pchData);
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy packet data to record
//
memcpy(
& precord->Data,
pchData,
bufLength );
precord->Data.WINS.dwMappingFlag =
FlipUnalignedDword( &precord->Data.Wins.dwMappingFlag );
precord->Data.WINS.dwLookupTimeout =
FlipUnalignedDword( &precord->Data.Wins.dwLookupTimeout );
precord->Data.WINS.dwCacheTimeout =
FlipUnalignedDword( &precord->Data.Wins.dwCacheTimeout );
precord->Data.WINS.cWinsServerCount =
FlipUnalignedDword( &precord->Data.Wins.cWinsServerCount );
return( precord );
}
PDNS_RECORD
Winsr_RecordRead(
IN OUT PDNS_RECORD pRR,
IN DNS_CHARSET OutCharSet,
IN OUT PCHAR pchStart,
IN PCHAR pchData,
IN PCHAR pchEnd
)
/*++
Routine Description:
Read WINSR record.
Arguments:
pRR - ptr to record with RR set context
pchStart - start of DNS message
pchData - ptr to RR data field
pchEnd - ptr to byte after data field
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
#define SIZEOF_WINSR_FIXED_DATA (sizeof(DNS_WINSR_DATA)-sizeof(PCHAR))
PDNS_RECORD precord;
WORD bufLength;
WORD nameLength;
CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
PCHAR pchstart;
//
// read WINSR domain name
// - name is after fixed length integer data
pchstart = pchData;
pchData += SIZEOF_WINSR_FIXED_DATA;
pchData = Dns_ReadPacketName(
nameBuffer,
& nameLength,
NULL,
NULL,
pchData,
pchStart,
pchEnd );
if ( pchData != pchEnd )
{
DNS_PRINT(( "ERROR: bad packet name.\n" ));
SetLastError( DNS_ERROR_INVALID_NAME );
return( NULL );
}
//
// determine required buffer length and allocate
//
bufLength = sizeof(DNS_WINSR_DATA);
bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
//
// copy fixed data
// - copy first so flipping is aligned
memcpy(
& precord->Data,
pchstart,
SIZEOF_WINSR_FIXED_DATA );
precord->Data.WINSR.dwMappingFlag = ntohl( precord->Data.WINSR.dwMappingFlag );
precord->Data.WINSR.dwLookupTimeout = ntohl( precord->Data.WINSR.dwLookupTimeout );
precord->Data.WINSR.dwCacheTimeout = ntohl( precord->Data.WINSR.dwCacheTimeout );
//
// write hostname into buffer, immediately following PTR data struct
//
precord->Data.WINSR.pNameResultDomain = (PCHAR)&precord->Data + sizeof(DNS_WINSR_DATA);
Dns_NameCopy(
precord->Data.WINSR.pNameResultDomain,
NULL, // no buffer length
nameBuffer,
nameLength,
DnsCharSetUtf8,
OutCharSet
);
return( precord );
}
//
// RR read to packet jump table
//
RR_READ_FUNCTION RR_ReadTable[] =
{
NULL, // ZERO
A_RecordRead, // A
Ptr_RecordRead, // NS
Ptr_RecordRead, // MD
Ptr_RecordRead, // MF
Ptr_RecordRead, // CNAME
Soa_RecordRead, // SOA
Ptr_RecordRead, // MB
Ptr_RecordRead, // MG
Ptr_RecordRead, // MR
Flat_RecordRead, // NULL
Wks_RecordRead, // WKS
Ptr_RecordRead, // PTR
Txt_RecordRead, // HINFO
Minfo_RecordRead, // MINFO
Mx_RecordRead, // MX
Txt_RecordRead, // TXT
Minfo_RecordRead, // RP
Mx_RecordRead, // AFSDB
Txt_RecordRead, // X25
Txt_RecordRead, // ISDN
Mx_RecordRead, // RT
NULL, // NSAP
NULL, // NSAPPTR
NULL, // SIG
NULL, // KEY
NULL, // PX
NULL, // GPOS
Flat_RecordRead, // AAAA
NULL, // LOC
NULL, // NXT
NULL, // EID
NULL, // NIMLOC
Srv_RecordRead, // SRV
Atma_RecordRead, // ATMA
NULL, // NAPTR
NULL, // KX
NULL, // CERT
NULL, // A6
NULL, // DNAME
NULL, // SINK
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)
//
// Pseudo record types
//
Tkey_RecordRead, // TKEY
Tsig_RecordRead, // TSIG
//
// MS only types
//
Wins_RecordRead, // WINS
Winsr_RecordRead, // WINSR
};
//
// End rrread.c
//