windows-nt/Source/XPSP1/NT/ds/dns/dnslib/rrcopy.c
2020-09-26 16:20:57 +08:00

1113 lines
21 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
rrcopy.c
Abstract:
Domain Name System (DNS) Library
Copy resource record routines.
Author:
Jim Gilroy (jamesg) February, 1997
Revision History:
--*/
#include "local.h"
PDNS_RECORD
ARecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy A record data from packet.
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
precord = Dns_AllocateRecord( sizeof(IP_ADDRESS) );
if ( !precord )
{
return NULL;
}
precord->Data.A.IpAddress = pRR->Data.A.IpAddress;
return precord;
}
PDNS_RECORD
PtrRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy PTR compatible record.
Includes: NS, PTR, CNAME, MB, MR, MG, MD, MF
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
precord = Dns_AllocateRecord( sizeof( DNS_PTR_DATA ) );
if ( !precord )
{
return NULL;
}
precord->Data.PTR.pNameHost = Dns_NameCopyAllocate(
pRR->Data.PTR.pNameHost,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( ! precord->Data.PTR.pNameHost )
{
FREE_HEAP( precord );
return NULL;
}
FLAG_FreeData( precord ) = TRUE;
return precord;
}
PDNS_RECORD
SoaRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy SOA record.
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
LPSTR pname;
precord = Dns_AllocateRecord( sizeof( DNS_SOA_DATA ) );
if ( !precord )
{
return NULL;
}
//
// copy integer data
//
memcpy(
& precord->Data.SOA.dwSerialNo,
& pRR->Data.SOA.dwSerialNo,
SIZEOF_SOA_FIXED_DATA );
//
// create copy of primary and admin
//
pname = Dns_NameCopyAllocate(
pRR->Data.SOA.pNamePrimaryServer,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord );
return NULL;
}
precord->Data.SOA.pNamePrimaryServer = pname;
pname = Dns_NameCopyAllocate(
pRR->Data.SOA.pNameAdministrator,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord->Data.SOA.pNamePrimaryServer );
FREE_HEAP( precord );
return NULL;
}
precord->Data.SOA.pNameAdministrator = pname;
FLAG_FreeData( precord ) = TRUE;
return precord;
}
PDNS_RECORD
MinfoRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy MINFO and RP records from wire.
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
LPSTR pname;
precord = Dns_AllocateRecord( sizeof( DNS_MINFO_DATA ) );
if ( !precord )
{
return NULL;
}
//
// create copy of name fields
//
pname = Dns_NameCopyAllocate(
pRR->Data.MINFO.pNameMailbox,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord );
return NULL;
}
precord->Data.MINFO.pNameMailbox = pname;
pname = Dns_NameCopyAllocate(
pRR->Data.MINFO.pNameErrorsMailbox,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord->Data.MINFO.pNameMailbox );
FREE_HEAP( precord );
return NULL;
}
precord->Data.MINFO.pNameErrorsMailbox = pname;
FLAG_FreeData( precord ) = TRUE;
return precord;
}
PDNS_RECORD
MxRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy MX compatible record from wire.
Includes: MX, RT, AFSDB
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
PCHAR pname;
precord = Dns_AllocateRecord( sizeof( DNS_MX_DATA ) );
if ( !precord )
{
return NULL;
}
// MX preference value
// RT preference
// AFSDB subtype
precord->Data.MX.wPreference = pRR->Data.MX.wPreference;
// MX exchange
// RT exchange
// AFSDB hostname
// - name immediately follows MX data struct
pname = Dns_NameCopyAllocate(
pRR->Data.MX.pNameExchange,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord );
return NULL;
}
precord->Data.MX.pNameExchange = pname;
FLAG_FreeData( precord ) = TRUE;
return precord;
}
PDNS_RECORD
TxtRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy TXT compatible records.
Includes: TXT, X25, HINFO, ISDN
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
WORD bufLength = sizeof( DNS_TXT_DATA );
INT count = pRR->Data.TXT.dwStringCount;
LPSTR * ppstringIn;
LPSTR * ppstringNew;
LPSTR pstring;
bufLength += (WORD)(sizeof(LPSTR) * count);
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return NULL;
}
precord->Data.TXT.dwStringCount = 0;
//
// copy each string
// - first string written immediately after string ptr list
// - each string written immediately after previous
//
ppstringIn = (LPSTR *) pRR->Data.TXT.pStringArray;
ppstringNew = (LPSTR *) precord->Data.TXT.pStringArray;
FLAG_FreeData( precord ) = TRUE;
while ( count-- )
{
pstring = Dns_StringCopyAllocate(
*ppstringIn,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( ! pstring )
{
Dns_RecordFree( precord );
return NULL;
}
*ppstringNew = pstring;
precord->Data.TXT.dwStringCount += 1;
ppstringIn++;
ppstringNew++;
}
return precord;
}
PDNS_RECORD
FlatRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy flat data compatible record.
Includes: AAAA
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
//
// allocate given datalength
//
precord = Dns_AllocateRecord( pRR->wDataLength );
if ( !precord )
{
return( NULL );
}
//
// flat copy of data
//
memcpy(
& precord->Data,
& pRR->Data,
pRR->wDataLength );
return( precord );
}
PDNS_RECORD
SrvRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy SRV compatible record from wire.
Includes: SRV, RT, AFSDB
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
PCHAR pname;
precord = Dns_AllocateRecord( sizeof( DNS_SRV_DATA ) );
if ( !precord )
{
return NULL;
}
// copy integer data
precord->Data.SRV.wPriority = pRR->Data.SRV.wPriority;
precord->Data.SRV.wWeight = pRR->Data.SRV.wWeight;
precord->Data.SRV.wPort = pRR->Data.SRV.wPort;
// copy target name
pname = Dns_NameCopyAllocate(
pRR->Data.SRV.pNameTarget,
0, // length unknown
CharSetIn,
CharSetOut
);
if ( !pname )
{
FREE_HEAP( precord );
return NULL;
}
precord->Data.SRV.pNameTarget = pname;
SET_FREE_DATA( precord );
return precord;
}
PDNS_RECORD
AtmaRecordCopy(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy Atma compatible record from wire.
Includes:
Arguments:
pRR - RR to copy
Return Value:
Ptr to new record if successful.
NULL on failure.
--*/
{
PDNS_RECORD precord;
WORD bufLength;
//
// determine required buffer length and allocate
//
bufLength = sizeof(DNS_ATMA_DATA) + DNS_ATMA_MAX_ADDR_LENGTH ;
precord = Dns_AllocateRecord( bufLength );
if ( !precord )
{
return( NULL );
}
// copy integer data
precord->Data.ATMA.AddressType = pRR->Data.ATMA.AddressType;
if ( precord->Data.ATMA.AddressType == DNS_ATMA_FORMAT_E164 )
{
precord->wDataLength = (WORD) strlen(pRR->Data.ATMA.Address);
if ( precord->wDataLength > DNS_ATMA_MAX_ADDR_LENGTH )
{
precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
}
strncpy(
precord->Data.ATMA.Address,
pRR->Data.ATMA.Address,
precord->wDataLength );
}
else
{
precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
memcpy(
precord->Data.ATMA.Address,
pRR->Data.ATMA.Address,
precord->wDataLength );
}
return( precord );
}
//
// RR copy jump table
//
RR_COPY_FUNCTION RRCopyTable[] =
{
NULL, // ZERO
ARecordCopy, // A
PtrRecordCopy, // NS
PtrRecordCopy, // MD
PtrRecordCopy, // MF
PtrRecordCopy, // CNAME
SoaRecordCopy, // SOA
PtrRecordCopy, // MB
PtrRecordCopy, // MG
PtrRecordCopy, // MR
NULL, // NULL
NULL, //WksRecordCopy, // WKS
PtrRecordCopy, // PTR
TxtRecordCopy, // HINFO
MinfoRecordCopy, // MINFO
MxRecordCopy, // MX
TxtRecordCopy, // TXT
MinfoRecordCopy, // RP
MxRecordCopy, // AFSDB
TxtRecordCopy, // X25
TxtRecordCopy, // ISDN
MxRecordCopy, // RT
NULL, // NSAP
NULL, // NSAPPTR
NULL, // SIG
NULL, // KEY
NULL, // PX
NULL, // GPOS
FlatRecordCopy, // AAAA
NULL, // LOC
NULL, // NXT
NULL, // EID
NULL, // NIMLOC
SrvRecordCopy, // SRV
AtmaRecordCopy, // 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
//
NULL, // TKEY
NULL, // TSIG
//
// MS only types
//
FlatRecordCopy, // WINS
NULL, // WINSR
};
//
// Generic copy functions
//
PDNS_RECORD
privateRecordCopy(
IN PDNS_RECORD pRecord,
IN PDNS_RECORD pPrevIn,
IN PDNS_RECORD pPrevCopy,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy record to as member of record set.
The previous records allow suppression of owner name copy when copying
RR set.
Arguments:
pRecord - record to copy
pPrevIn - previous incoming record copied
pPrevCopy - copy of pPrevIn in new set
CharSetIn - input record character set; OPTIONAL
if zero, pRecord must have CharSet;
if non-zero, pRecord must have zero or matching CharSet;
allow this to be specified independently of pRecord, to handle
conversion of user supplied records, which we do not want to
modify
CharSetOut - desired record character set
Return Value:
Ptr to copy of record in desired character set.
NULL on error.
--*/
{
PDNS_RECORD prr;
WORD index;
DNS_CHARSET recordCharSet;
DNSDBG( TRACE, ( "privateRecordCopy( %p )\n", pRecord ));
//
// input character set
// allow specification of input character set to handle case
// of user created records, but if input record has a set
// then it's assumed to be valid
// so validity check:
// - CharSetIn == 0 => use record's != 0 set
// - record's set == 0 => use CharSetIn != 0
// - CharSetIn == record's set
//
recordCharSet = RECORD_CHARSET( pRecord );
if ( recordCharSet )
{
ASSERT( CharSetIn == 0 || CharSetIn == recordCharSet );
CharSetIn = recordCharSet;
}
else // record has no charset
{
if ( CharSetIn == 0 )
{
ASSERT( FALSE );
goto Failed;
}
}
//
// copy record data
//
if ( pRecord->wDataLength != 0 )
{
index = INDEX_FOR_TYPE( pRecord->wType );
DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
if ( !index || !RRCopyTable[ index ] )
{
DNS_PRINT((
"WARNING: No copy routine for type = %d\n"
"\tdoing flat copy of record at %p\n",
pRecord->wType,
pRecord ));
prr = FlatRecordCopy(
pRecord,
CharSetIn,
CharSetOut );
}
else
{
prr = RRCopyTable[ index ](
pRecord,
CharSetIn,
CharSetOut );
}
}
else // no data record
{
prr = FlatRecordCopy(
pRecord,
CharSetIn,
CharSetOut );
}
if ( !prr )
{
goto Failed;
}
//
// copy record structure fields
// - type
// - TTL
// - flags
//
prr->dwTtl = pRecord->dwTtl;
prr->wType = pRecord->wType;
prr->Flags.S.Section = pRecord->Flags.S.Section;
prr->Flags.S.Delete = pRecord->Flags.S.Delete;
prr->Flags.S.CharSet = CharSetOut;
//
// copy name
//
if ( pRecord->pName )
{
//
// - if incoming name has FreeOwner set, then always copy
// as never know when incoming set will be tossed
//
// - then check if incoming name same as previous incoming
// name in which case we can use previous copied name
//
// - otherwise full copy of name
//
if ( !FLAG_FreeOwner( pRecord ) &&
pPrevIn && pPrevCopy &&
pRecord->pName == pPrevIn->pName )
{
prr->pName = pPrevCopy->pName;
}
else
{
prr->pName = Dns_NameCopyAllocate(
pRecord->pName,
0, // unknown length
CharSetIn,
CharSetOut
);
if ( !prr->pName )
{
FREE_HEAP( prr );
goto Failed;
}
FLAG_FreeOwner( prr ) = TRUE;
}
}
DNSDBG( TRACE, (
"Leaving privateRecordCopy(%p) = %p.\n",
pRecord,
prr ));
return( prr );
Failed:
DNSDBG( TRACE, (
"privateRecordCopy(%p) failed\n",
pRecord ));
return( NULL );
}
PDNS_RECORD
WINAPI
Dns_RecordCopyEx(
IN PDNS_RECORD pRecord,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy record.
Arguments:
pRecord - record to copy
CharSetIn - incoming record's character set
CharSetOut -- char set for resulting record
Return Value:
Ptr to copy of record in desired character set.
NULL on error.
--*/
{
DNSDBG( TRACE, ( "Dns_RecordCopyEx( %p )\n", pRecord ));
//
// call private copy routine
// - set optional ptrs to cause full owner name copy
//
return privateRecordCopy(
pRecord,
NULL,
NULL,
CharSetIn,
CharSetOut );
}
PDNS_RECORD
WINAPI
Dns_RecordCopy_W(
IN PDNS_RECORD pRecord
)
/*++
Routine Description:
Copy record.
Arguments:
pRecord - unicode record to copy to unicode
Return Value:
Ptr to copy of record in desired character set.
NULL on error.
--*/
{
DNSDBG( TRACE, ( "Dns_RecordCopy( %p )\n", pRecord ));
//
// call private copy routine
// - set optional ptrs to cause full owner name copy
//
return privateRecordCopy(
pRecord,
NULL,
NULL,
DnsCharSetUnicode,
DnsCharSetUnicode );
}
PDNS_RECORD
WINAPI
Dns_RecordCopy_A(
IN PDNS_RECORD pRecord
)
/*++
Routine Description:
Copy record.
Arguments:
pRecord - ANSI record to copy to ANSI
Return Value:
Ptr to copy of record in desired character set.
NULL on error.
--*/
{
DNSDBG( TRACE, ( "Dns_RecordCopy( %p )\n", pRecord ));
//
// call private copy routine
// - set optional ptrs to cause full owner name copy
//
return privateRecordCopy(
pRecord,
NULL,
NULL,
DnsCharSetAnsi,
DnsCharSetAnsi );
}
//
// Record set copy
//
PDNS_RECORD
Dns_RecordSetCopyEx(
IN PDNS_RECORD pRR,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Copy record set, converting to UTF8 if necessary.
Arguments:
pRR - incoming record set
CharSetIn - incoming record's character set
CharSetOut -- char set for resulting record
Return Value:
Ptr to new record set, if successful.
NULL on error.
--*/
{
return Dns_RecordListCopyEx(
pRR,
0, // no screening flags
CharSetIn,
CharSetOut
);
}
PDNS_RECORD
Dns_RecordListCopyEx(
IN PDNS_RECORD pRR,
IN DWORD ScreenFlag,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Screened copy of record set.
Arguments:
pRR - incoming record set
ScreenFlag - flag with record screening parameters
CharSetIn - incoming record's character set
CharSetOut -- char set for resulting record
Return Value:
Ptr to new record set, if successful.
NULL on error.
--*/
{
PDNS_RECORD prr; // most recent copied
PDNS_RECORD prevIn; // previous in set being copied
DNS_RRSET rrset;
DNSDBG( TRACE, (
"Dns_RecordListCopyEx( %p, %08x, %d, %d )\n",
pRR,
ScreenFlag,
CharSetIn,
CharSetOut ));
// init copy rrset
DNS_RRSET_INIT( rrset );
//
// loop through RR set, add records to either match or diff sets
//
prevIn = NULL;
prr = NULL;
while ( pRR )
{
// skip copy on record not matching copy criteria
if ( ScreenFlag )
{
if ( !Dns_ScreenRecord( pRR, ScreenFlag ) )
{
pRR = pRR->pNext;
continue;
}
}
prr = privateRecordCopy(
pRR,
prevIn,
prr, // previous rr copied
CharSetIn,
CharSetOut
);
if ( prr )
{
DNS_RRSET_ADD( rrset, prr );
prevIn = pRR;
pRR = pRR->pNext;
continue;
}
// if fail, toss entire new set
Dns_RecordListFree( rrset.pFirstRR );
return( NULL );
}
return( rrset.pFirstRR );
}
//
// End rrcopy.c
//