|
|
/*++
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 ); }
//
// Reverse record creation
//
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 PDNS_ADDR pAddr, 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:
pAddr -- addr (IP4 or IP6) to map into PTR
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 = NULL; DWORD family;
//
// create reverse lookup name
// - note this is external allocation
//
family = DnsAddr_Family( pAddr );
if ( family == AF_INET ) { IP4_ADDRESS ip = DnsAddr_GetIp4(pAddr);
if ( RecordCharSet == DnsCharSetUnicode ) { pname = (PCHAR) Dns_Ip4AddressToReverseNameAlloc_W( ip ); } else { pname = Dns_Ip4AddressToReverseNameAlloc_A( ip ); } } else if ( family == AF_INET6 ) { PIP6_ADDRESS p6 = DnsAddr_GetIp6Ptr(pAddr);
if ( RecordCharSet == DnsCharSetUnicode ) { pname = (PCHAR) Dns_Ip6AddressToReverseNameAlloc_W( *p6 ); } else { pname = Dns_Ip6AddressToReverseNameAlloc_A( *p6 ); } }
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 PDNS_ADDR pAddr, 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:
pAddr -- addr (IP4 or IP6) to map into PTR
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( pAddr, (PCHAR) nameBuffer, Ttl, NameCharSet, RecordCharSet ); }
//
// Forward record creation
//
PDNS_RECORD Dns_CreateARecord( IN PDNS_NAME pOwnerName, IN IP4_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_CreateAAAARecordFromDnsAddr( IN PDNS_NAME pOwnerName, IN PDNS_ADDR pAddr, IN DWORD Ttl, IN DNS_CHARSET NameCharSet, IN DNS_CHARSET RecordCharSet ) /*++
Routine Description:
Create A record.
Arguments:
pOwnerName -- owner name
pAddr -- Ptr to DNS_ADDR
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 = Dns_CreateAAAARecord( pOwnerName, * (PIP6_ADDRESS) &pAddr->SockaddrIn6.sin6_addr, Ttl, NameCharSet, RecordCharSet ); if ( !prr ) { return( NULL ); }
//
// slap scope into reserved field
//
prr->dwReserved = pAddr->SockaddrIn6.sin6_scope_id;
return( prr ); }
PDNS_RECORD Dns_CreateForwardRecord( IN PDNS_NAME pOwnerName, IN WORD wType, OPTIONAL IN PDNS_ADDR pAddr, 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
wType -- type, if specified; zero for getting type from pAddr
pAddr -- ptr to DNS_ADDR
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
//
if ( DnsAddr_IsIp4( pAddr ) ) { if ( wType == 0 || wType == DNS_TYPE_A ) { return Dns_CreateARecord( pOwnerName, DnsAddr_GetIp4( pAddr ), Ttl, NameCharSet, RecordCharSet ); }
} else if ( DnsAddr_IsIp6( pAddr ) ) { if ( wType == 0 || wType == DNS_TYPE_AAAA ) { return Dns_CreateAAAARecordFromDnsAddr( pOwnerName, pAddr, Ttl, NameCharSet, RecordCharSet ); } }
return NULL; }
PDNS_RECORD Dns_CreateForwardRecordFromIp6( IN PDNS_NAME pOwnerName, IN PIP6_ADDRESS 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 -- IP6 address
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
//
if ( IP6_IS_ADDR_V4MAPPED( pIp ) ) { return Dns_CreateARecord( pOwnerName, IP6_GET_V4_ADDR( pIp ), Ttl, NameCharSet, RecordCharSet ); } else { return Dns_CreateAAAARecord( pOwnerName, *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, OPTIONAL IN DWORD Ttl ) /*++
Routine Description:
Create record for IP string query.
Arguments:
pwsName -- name that may be IP string query
wType -- type of query; OPTIONAL, if zero type derived from string
Return Value:
Ptr to record for query, if query name\type is IP. NULL if query not for IP.
--*/ { DNS_ADDR addr; 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
//
if ( wType == DNS_TYPE_A || wType == 0 ) { IP4_ADDRESS ip4; PCWSTR pdot; DWORD count;
if ( ! Dns_Ip4StringToAddress_W( & ip4, (PWSTR) pwsName ) ) { goto Try6; }
// verify three dot form w.x.y.z
pdot = pwsName; count = 3; while ( count-- ) { pdot = wcschr( pdot, L'.' ); if ( !pdot || !*++pdot ) { goto Try6; } }
DnsAddr_BuildFromIp4( &addr, ip4, 0 );
wType = DNS_TYPE_A; goto Build; }
Try6:
if ( wType == DNS_TYPE_AAAA || wType == 0 ) { // this will convert any form,
// but set type==AAAA to fail record build if
// did NOT build IP6
if ( Dns_StringToDnsAddr_W( & addr, (PWSTR) pwsName ) ) { wType = DNS_TYPE_AAAA; goto Build; } }
return NULL; // no match
Build:
//
// name is IP string -- build record
//
prr = Dns_CreateForwardRecord( (PDNS_NAME) pwsName, wType, & addr, Ttl, DnsCharSetUnicode, DnsCharSetUnicode );
DNSDBG( TRACE, ( "Create record %p for IP string %S type %d.\n", prr, pwsName, wType ));
return prr; }
//
// End rralloc.c
//
|