|
|
/*++
Copyright (c) 1996-2001 Microsoft Corporation
Module Name:
rralloc.c
Abstract:
Domain Name System (DNS) Library
Resource record allocation \ creation routines.
Author:
Jim Gilroy (jamesg) January, 1997
Environment:
User Mode - Win32
Revision History:
--*/
#include "local.h"
#define SET_FLAGS(Flags, value) \
( *(PWORD)&(Flags) = value )
PDNS_RECORD WINAPI Dns_AllocateRecord( IN WORD wBufferLength ) /*++
Routine Description:
Allocate record structure.
Arguments:
wBufferLength - desired buffer length (beyond structure header)
Return Value:
Ptr to message buffer. NULL on error.
--*/ { PDNS_RECORD prr;
prr = ALLOCATE_HEAP( SIZEOF_DNS_RECORD_HEADER + wBufferLength ); if ( prr == NULL ) { SetLastError( DNS_ERROR_NO_MEMORY ); return( NULL ); } RtlZeroMemory( prr, SIZEOF_DNS_RECORD_HEADER );
// as first cut, set datalength to buffer length
prr->wDataLength = wBufferLength; return( prr ); }
VOID WINAPI Dns_RecordFree( IN OUT PDNS_RECORD pRecord ) /*++
Routine Description:
Free a record
Arguments:
pRecord -- record list to free
Return Value:
None.
--*/ { DNSDBG( HEAP, ( "Dns_RecordFree( %p )\n", pRecord ));
// handle NULL for convenience
if ( !pRecord ) { return; }
// free owner name?
if ( FLAG_FreeOwner( pRecord ) ) { FREE_HEAP( pRecord->pName ); }
//
// free data -- but only if flag set
//
// note: even if we fix copy functions to do atomic
// allocations, we'll still have to have free to
// handle RPC allocations
// (unless we very cleverly, treated RPC as flat blob, then
// did fix up (to offsets before and afterward)
//
if ( FLAG_FreeData( pRecord ) ) { switch( pRecord->wType ) { case DNS_TYPE_A: break;
case DNS_TYPE_PTR: case DNS_TYPE_NS: case DNS_TYPE_CNAME: case DNS_TYPE_MB: case DNS_TYPE_MD: case DNS_TYPE_MF: case DNS_TYPE_MG: case DNS_TYPE_MR:
if ( pRecord->Data.PTR.pNameHost ) { FREE_HEAP( pRecord->Data.PTR.pNameHost ); } break;
case DNS_TYPE_SOA:
if ( pRecord->Data.SOA.pNamePrimaryServer ) { FREE_HEAP( pRecord->Data.SOA.pNamePrimaryServer ); } if ( pRecord->Data.SOA.pNameAdministrator ) { FREE_HEAP( pRecord->Data.SOA.pNameAdministrator ); } break;
case DNS_TYPE_MINFO: case DNS_TYPE_RP:
if ( pRecord->Data.MINFO.pNameMailbox ) { FREE_HEAP( pRecord->Data.MINFO.pNameMailbox ); } if ( pRecord->Data.MINFO.pNameErrorsMailbox ) { FREE_HEAP( pRecord->Data.MINFO.pNameErrorsMailbox ); } break;
case DNS_TYPE_MX: case DNS_TYPE_AFSDB: case DNS_TYPE_RT:
if ( pRecord->Data.MX.pNameExchange ) { FREE_HEAP( pRecord->Data.MX.pNameExchange ); } break;
case DNS_TYPE_HINFO: case DNS_TYPE_ISDN: case DNS_TYPE_TEXT: case DNS_TYPE_X25:
{ DWORD iter; DWORD count = pRecord->Data.TXT.dwStringCount;
for ( iter = 0; iter < count; iter++ ) { if ( pRecord->Data.TXT.pStringArray[iter] ) { FREE_HEAP( pRecord->Data.TXT.pStringArray[iter] ); } } break; }
case DNS_TYPE_SRV:
if ( pRecord->Data.SRV.pNameTarget ) { FREE_HEAP( pRecord->Data.SRV.pNameTarget ); } break;
case DNS_TYPE_WINSR:
if ( pRecord->Data.WINSR.pNameResultDomain ) { FREE_HEAP( pRecord->Data.WINSR.pNameResultDomain ); } break;
default:
// other types -- A, AAAA, ATMA, WINS, NULL,
// have no internal pointers
break; } }
// for catching heap problems
pRecord->pNext = DNS_BAD_PTR; pRecord->pName = DNS_BAD_PTR;
FREE_HEAP( pRecord ); }
VOID WINAPI Dns_RecordListFree( IN OUT PDNS_RECORD pRecord ) /*++
Routine Description:
Free list of records.
Arguments:
pRecord -- record list to free
Return Value:
None.
--*/ { PDNS_RECORD pnext;
DNSDBG( TRACE, ( "Dns_RecordListFree( %p )\n", pRecord ));
//
// loop through and free every RR in list
//
while ( pRecord ) { pnext = pRecord->pNext;
Dns_RecordFree( pRecord );
pRecord = pnext; } }
VOID WINAPI Dns_RecordListFreeEx( IN OUT PDNS_RECORD pRecord, IN BOOL fFreeOwner ) /*++
Routine Description:
Free list of records.
DCR: RecordListFreeEx (no free owner option) is probably useless
Note: owner name is freed ONLY when indicated by flag; other ptrs are considered to be either 1) internal as when records read from wire or copied 2) external and to be freed by record creator
Arguments:
pRecord -- record list to free
fFreeOwner -- flag indicating owner name should be freed
Return Value:
None.
--*/ { PDNS_RECORD pnext;
DNSDBG( TRACE, ( "Dns_RecordListFreeEx( %p, %d )\n", pRecord, fFreeOwner ));
//
// loop through and free every RR in list
//
while ( pRecord ) { pnext = pRecord->pNext;
// free owner name?
// - if "FreeOwner" flag NOT set, then don't free
if ( !fFreeOwner ) { FLAG_FreeOwner( pRecord ) = FALSE; }
// free record
Dns_RecordFree( pRecord );
pRecord = pnext; } }
//
// Special record type creation routines
//
PDNS_RECORD CreateRecordBasic( IN PDNS_NAME pOwnerName, IN BOOL fCopyName, IN WORD wType, IN WORD wDataLength, IN DWORD AllocLength, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create record of arbitary type.
Helper function to wrap up - record alloc - name alloc - basic setup
Arguments:
pOwnerName -- owner name
fCopyName -- TRUE - make copy of owner name FALSE - use directly
wType -- type
AllocLength -- allocaction length, including any imbedded data
wDataLength -- data length to set
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PDNS_RECORD precord; PDNS_RECORD prr; PCHAR pname; DWORD bufLength;
//
// alloc record
//
prr = Dns_AllocateRecord( (WORD)AllocLength ); if ( !prr ) { return( NULL ); }
//
// copy owner name
//
if ( fCopyName && pOwnerName ) { pname = Dns_NameCopyAllocate( pOwnerName, 0, // length unknown
NameCharSet, RecordCharSet ); if ( !pname ) { FREE_HEAP( prr ); return( NULL ); } } else { pname = pOwnerName; } //
// set fields
// - name, type and charset
// - TTL, section left zero
// - FreeData is specifically off
//
prr->pName = pname; prr->wType = wType; prr->wDataLength = wDataLength; SET_FREE_OWNER(prr); prr->Flags.S.CharSet = RecordCharSet; prr->dwTtl = Ttl;
return( prr ); }
PDNS_RECORD Dns_CreateFlatRecord( IN PDNS_NAME pOwnerName, IN WORD wType, IN PCHAR pData, IN DWORD DataLength, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create flat record.
Arguments:
pOwnerName -- owner name
wType -- record type
pData -- ptr to data for record
DataLength -- length (in bytes) of data
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PDNS_RECORD prr;
//
// determine record size
// - record buffer will include hostname
//
prr = CreateRecordBasic( pOwnerName, TRUE, // copy name
wType, (WORD) DataLength, // datalength
DataLength, // alloc datalength
Ttl, NameCharSet, RecordCharSet ); if ( !prr ) { return( NULL ); }
//
// copy in data
//
RtlCopyMemory( (PBYTE) &prr->Data, pData, DataLength );
return( prr ); }
PDNS_RECORD Dns_CreatePtrTypeRecord( IN PDNS_NAME pOwnerName, IN BOOL fCopyName, IN PDNS_NAME pTargetName, IN WORD wType, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create PTR type (single-indirection) record.
This can be used to create any "PTR-type" record: PTR, CNAME, NS, etc.
Arguments:
pOwnerName -- owner name
fCopyName -- TRUE - make copy of owner name FALSE - use directly
pTargetName -- target name
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PDNS_RECORD precord; PDNS_RECORD prr; PCHAR pname; DWORD bufLength;
//
// determine record size
// - record buffer will include hostname
//
bufLength = Dns_GetBufferLengthForNameCopy( pTargetName, 0, // length unknown
NameCharSet, RecordCharSet ); if ( !bufLength ) { return( NULL ); }
//
// create record
//
prr = CreateRecordBasic( pOwnerName, fCopyName, wType, sizeof(DNS_PTR_DATA), // data length
(sizeof(DNS_PTR_DATA) + bufLength), // alloc length
Ttl, NameCharSet, RecordCharSet ); if ( !prr ) { return( NULL ); }
//
// write target name into buffer, immediately following PTR data struct
//
prr->Data.PTR.pNameHost = (PCHAR)&prr->Data + sizeof(DNS_PTR_DATA);
Dns_NameCopy( prr->Data.PTR.pNameHost, NULL, pTargetName, 0, NameCharSet, RecordCharSet );
return( prr ); }
PDNS_RECORD Dns_CreatePtrRecordEx( IN PIP_UNION pIp, IN PDNS_NAME pszHostName, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create PTR record from IP address and hostname.
Arguments:
pIp -- IP union (IP4 or IP6)
pszHostName -- host name, FULL FQDN
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PCHAR pname;
//
// create reverse lookup name
// - note this is external allocation
//
if ( IPUNION_IS_IP4( pIp ) ) { IP4_ADDRESS ip = IPUNION_GET_IP4(pIp);
if ( RecordCharSet == DnsCharSetUnicode ) { pname = (PCHAR) Dns_Ip4AddressToReverseNameAlloc_W( ip ); } else { pname = Dns_Ip4AddressToReverseNameAlloc_A( ip ); } } else { IP6_ADDRESS ip = IPUNION_GET_IP6(pIp);
if ( RecordCharSet == DnsCharSetUnicode ) { pname = (PCHAR) Dns_Ip6AddressToReverseNameAlloc_W( ip ); } else { pname = Dns_Ip6AddressToReverseNameAlloc_A( ip ); } }
if ( !pname ) { return( NULL ); }
//
// build record
//
return Dns_CreatePtrTypeRecord( pname, FALSE, // don't copy IP
pszHostName, // target name
DNS_TYPE_PTR, Ttl, NameCharSet, RecordCharSet ); }
PDNS_RECORD Dns_CreatePtrRecordExEx( IN PIP_UNION pIp, IN PSTR pszHostName, IN PSTR pszDomainName, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create PTR record from hostname and domain name.
Helper function for DHCP registrations when hostname and domain name are separate and both required.
Arguments:
pIp -- IP union (IP4 or IP6)
pszHostName -- host name (single label)
pszDomainName -- domain name
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { WCHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
DNSDBG( TRACE, ( "Dns_CreatePtrRecordExEx()\n" ));
//
// build appended name
//
// DCR: could require just host name and check that
// either domain exists or hostname is full
//
if ( !pszHostName || !pszDomainName ) { return NULL; }
if ( NameCharSet != DnsCharSetUnicode ) { if ( ! Dns_NameAppend_A( (PCHAR) nameBuffer, DNS_MAX_NAME_BUFFER_LENGTH, pszHostName, pszDomainName ) ) { DNS_ASSERT( FALSE ); return NULL; } } else { if ( ! Dns_NameAppend_W( (PWCHAR) nameBuffer, DNS_MAX_NAME_BUFFER_LENGTH, (PWSTR) pszHostName, (PWSTR) pszDomainName ) ) { DNS_ASSERT( FALSE ); return NULL; } }
//
// build record
//
return Dns_CreatePtrRecordEx( pIp, (PCHAR) nameBuffer, Ttl, NameCharSet, RecordCharSet ); }
PDNS_RECORD Dns_CreateARecord( IN PDNS_NAME pOwnerName, IN IP_ADDRESS Ip4Addr, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create A record.
Arguments:
pOwnerName -- owner name
Ip4Addr -- IP address
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PDNS_RECORD prr;
//
// determine record size
// - record buffer will include hostname
//
prr = CreateRecordBasic( pOwnerName, TRUE, // copy name
DNS_TYPE_A, sizeof(DNS_A_DATA), sizeof(DNS_A_DATA), Ttl, NameCharSet, RecordCharSet ); if ( !prr ) { return( NULL ); }
//
// set IP
//
prr->Data.A.IpAddress = Ip4Addr;
return( prr ); }
PDNS_RECORD Dns_CreateAAAARecord( IN PDNS_NAME pOwnerName, IN IP6_ADDRESS Ip6Addr, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create A record.
Arguments:
pOwnerName -- owner name
Ip6Addr -- IP6 address
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PDNS_RECORD prr;
//
// determine record size
// - record buffer will include hostname
//
prr = CreateRecordBasic( pOwnerName, TRUE, // copy name
DNS_TYPE_AAAA, sizeof(DNS_AAAA_DATA), sizeof(DNS_AAAA_DATA), Ttl, NameCharSet, RecordCharSet ); if ( !prr ) { return( NULL ); }
//
// set IP
//
prr->Data.AAAA.Ip6Address = Ip6Addr;
return( prr ); }
PDNS_RECORD Dns_CreateForwardRecord( IN PDNS_NAME pOwnerName, IN PIP_UNION pIp, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create forward lookup record.
This is just a shim to avoid duplicating selection logic.
Arguments:
pOwnerName -- owner name
pIp -- IP address union
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { //
// build desired type
//
// DCR: must add\choose A6
//
if ( IPUNION_IS_IP4( pIp ) ) { return Dns_CreateARecord( pOwnerName, IPUNION_GET_IP4(pIp), Ttl, NameCharSet, RecordCharSet ); } else { return Dns_CreateAAAARecord( pOwnerName, IPUNION_GET_IP6(pIp), Ttl, NameCharSet, RecordCharSet ); } }
PDNS_RECORD Dns_CreateForwardRecordForSockaddr( IN PDNS_NAME pOwnerName, IN PSOCKADDR pSockaddr, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create forward lookup record.
This is just a shim to avoid duplicating selection logic.
Arguments:
pOwnerName -- owner name
pSockaddr -- ptr to sockaddr
Ttl -- TTL
NameCharSet -- character set of name
RecordCharSet -- character set for resulting record
Return Value:
Ptr to PTR record. NULL on error.
--*/ { PFAMILY_INFO pinfo;
DNSDBG( TRACE, ( "Dns_CreateForwardRecordForSockaddr()\n" ));
pinfo = FamilyInfo_GetForSockaddr( pSockaddr ); if ( !pinfo ) { SetLastError( ERROR_INVALID_DATA ); return NULL; }
//
// build flat record of desired type
//
return Dns_CreateFlatRecord( pOwnerName, pinfo->DnsType, (PBYTE)pSockaddr + pinfo->OffsetToAddrInSockaddr, pinfo->LengthAddr, Ttl, NameCharSet, RecordCharSet ); }
PDNS_RECORD Dns_CreateRecordForIpString_W( IN PCWSTR pwsName, IN WORD wType, IN DWORD Ttl ) /*++
Routine Description:
Create record for IP string query.
Arguments:
pwsName -- name that may be IP string query
wType -- type of query
Return Value:
Ptr to record for query, if query name\type is IP. NULL if query not for IP.
--*/ { IP_UNION ipUnion; PDNS_RECORD prr;
DNSDBG( TRACE, ( "\nDns_CreateRecordForIpString( %S, wType = %d )\n", pwsName, wType ));
if ( !pwsName ) { return NULL; }
//
// support A or AAAA queries for IP strings
// - IP4 strings must be in w.x.y.z form otherwise
// we convert the all numeric names also
//
// DCR: need A6 support for direct query
//
if ( wType == DNS_TYPE_A ) { IP4_ADDRESS ip4; PCWSTR pdot; DWORD count;
if ( ! Dns_Ip4StringToAddress_W( & ip4, (PWSTR) pwsName ) ) { return NULL; }
// verify three dot form w.x.y.z
pdot = pwsName; count = 3; while ( count-- ) { pdot = wcschr( pdot, L'.' ); if ( !pdot || !*++pdot ) { return( NULL ); } }
IPUNION_SET_IP4( &ipUnion, ip4 ); } else if ( wType == DNS_TYPE_AAAA ) { IP6_ADDRESS ip6;
if ( ! Dns_Ip6StringToAddress_W( & ip6, (PWSTR) pwsName ) ) { return NULL; } IPUNION_SET_IP6( &ipUnion, ip6 ); } else { return NULL; }
//
// name is IP string -- build record
//
prr = Dns_CreateForwardRecord( (PDNS_NAME) pwsName, & ipUnion, Ttl, DnsCharSetUnicode, DnsCharSetUnicode );
DNSDBG( TRACE, ( "Create record %p for IP string %S type %d.\n", prr, pwsName, wType ));
return prr; }
//
// End rralloc.c
//
|