|
|
/*++
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
//
|