|
|
/*++
Copyright (c) 2001-2001 Microsoft Corporation
Module Name:
rrstrw.c
Abstract:
Domain Name System (DNS) Library
Record to string routines.
Author:
Jim Gilroy (jamesg) October 2001
Revision History:
--*/
#include "local.h"
//
// Min string lengths
// - in chars
// - includes spacing and terminating NULL
// - excludes name lengths
// - they are "rough" lengths
//
#define MIN_SRV_STRING_LENGTH (20) // 3*5u
#define MIN_MX_STRING_LENGTH (10) // 1*5u
#define MIN_SOA_STRING_LENGTH (60) // 5*10u
#define MIN_NAME_LENGTH (3) // space, name, NULL
//
// String writing context
//
// Blob to pass through write routines to preserve extensibility.
// For name\string writing must have access to record charset
// (so need record). If we ever want to use in context of
// zone file writing then would need zone context info.
//
typedef struct _RecordStringWriteContext { PDNS_RECORD pRecord; PSTR pZoneName; DWORD Flags; DNS_CHARSET CharSet; } STR_WRITE_CONTEXT, *PSTR_WRITE_CONTEXT;
//
// Private prototypes
//
//
// Record to string utilities
//
PCHAR WriteRecordDataNameToString( IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PCHAR pString, IN PSTR_WRITE_CONTEXT pContext ) /*++
Routine Description:
Write record name\string to string.
Arguments:
pBuf - position in to write record
pBufEnd - end of buffer
pString - record name\string
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { DWORD count; DWORD length = (DWORD) (pBufEnd - pBuf);
count = Dns_StringCopy( pBuf, & length, pString, 0, // string length unknown
RECORD_CHARSET( pContext->pRecord ), pContext->CharSet );
if ( count ) { return pBuf+count-1; } else { return NULL; } }
//
// Record to string type specific functions
//
PCHAR A_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write A record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { //if ( pRecord->wDataLength != sizeof(IP_ADDRESS) )
//{
// return NULL;
//}
if ( pBufEnd - pBuf < IP4_ADDRESS_STRING_BUFFER_LENGTH ) { return NULL; }
pBuf += sprintf( pBuf, "%d.%d.%d.%d", * ( (PUCHAR) &(pRR->Data.A) + 0 ), * ( (PUCHAR) &(pRR->Data.A) + 1 ), * ( (PUCHAR) &(pRR->Data.A) + 2 ), * ( (PUCHAR) &(pRR->Data.A) + 3 ) );
return( pBuf ); }
PCHAR Aaaa_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write AAAA record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { if ( pBufEnd - pBuf < IP6_ADDRESS_STRING_BUFFER_LENGTH ) { return NULL; }
pBuf = Dns_Ip6AddressToString_A( pBuf, & pRR->Data.AAAA.Ip6Address );
ASSERT( pBuf ); return( pBuf ); }
PCHAR Ptr_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write PTR compatible record. Includes: PTR, NS, CNAME, MB, MR, MG, MD, MF
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { // target host
return WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.PTR.pNameHost, pContext ); }
PCHAR Mx_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write SRV record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { // fixed fields
if ( pBufEnd - pBuf < 7 ) { return NULL; } pBuf += sprintf( pBuf, "%d ", pRR->Data.MX.wPreference );
// target host
return WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.MX.pNameExchange, pContext ); }
PCHAR Srv_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write SRV record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { // fixed fields
if ( pBufEnd - pBuf < MIN_SRV_STRING_LENGTH ) { return NULL; } pBuf += sprintf( pBuf, "%d %d %d ", pRR->Data.SRV.wPriority, pRR->Data.SRV.wWeight, pRR->Data.SRV.wPort );
// target host
return WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.SRV.pNameTarget, pContext ); }
PCHAR Soa_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write SOA record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { // primary server
pBuf = WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.SOA.pNamePrimaryServer, pContext );
if ( !pBuf || pBufEnd - pBuf < MIN_SOA_STRING_LENGTH ) { return NULL; }
// admin
pBuf += sprintf( pBuf, " " );
pBuf = WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.SOA.pNameAdministrator, pContext );
if ( !pBuf || pBufEnd - pBuf < MIN_SOA_STRING_LENGTH ) { return NULL; }
// fixed fields
pBuf += sprintf( pBuf, " %u %u %u %u %u", pRR->Data.SOA.dwSerialNo, pRR->Data.SOA.dwRefresh, pRR->Data.SOA.dwRetry, pRR->Data.SOA.dwExpire, pRR->Data.SOA.dwDefaultTtl );
return( pBuf ); }
PCHAR Minfo_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write MINFO type record.
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { // primary server
pBuf = WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.MINFO.pNameMailbox, pContext );
if ( !pBuf || pBufEnd - pBuf < MIN_NAME_LENGTH + 1 ) { return NULL; }
// admin
pBuf += sprintf( pBuf, " " );
pBuf = WriteRecordDataNameToString( pBuf, pBufEnd, pRR->Data.MINFO.pNameErrorsMailbox, pContext );
return pBuf; }
PCHAR Txt_StringWrite( IN PDNS_RECORD pRR, IN OUT PCHAR pBuf, IN PCHAR pBufEnd, IN PVOID pContext ) /*++
Routine Description:
Write TXT record. Includes: TXT, X25, HINFO, ISDN
Arguments:
pRR - ptr to database record
pBuf - position in to write record
pBufEnd - end of buffer
pContext - write context
Return Value:
Ptr to next location in buffer. NULL if out of space in buffer.
--*/ { PSTR * ppstring; INT i; INT count;
//
// loop through all strings in count
//
count = pRR->Data.TXT.dwStringCount; ppstring = pRR->Data.TXT.pStringArray;
for( i=0; i<count; i++ ) { // separator
if ( i > 0 ) { if ( pBufEnd - pBuf < MIN_NAME_LENGTH + 1 ) { return NULL; } pBuf += sprintf( pBuf, " " ); }
// string
pBuf = WriteRecordDataNameToString( pBuf, pBufEnd, *ppstring, pContext ); ppstring++;
if ( !pBuf ); { break; } }
return pBuf; }
//
// Write RR to file dispatch table
//
typedef PCHAR (* RR_STRING_WRITE_FUNCTION)( PDNS_RECORD, PCHAR, PCHAR, PVOID );
RR_STRING_WRITE_FUNCTION RR_StringWriteTable[] = { //RawRecord_StringWrite, // ZERO -- default for unknown types
NULL,
A_StringWrite, // A
Ptr_StringWrite, // NS
Ptr_StringWrite, // MD
Ptr_StringWrite, // MF
Ptr_StringWrite, // CNAME
Soa_StringWrite, // SOA
Ptr_StringWrite, // MB
Ptr_StringWrite, // MG
Ptr_StringWrite, // MR
//RawRecord_StringWrite, // NULL
NULL, // NULL
NULL, // WKS
Ptr_StringWrite, // PTR
Txt_StringWrite, // HINFO
Minfo_StringWrite, // MINFO
Mx_StringWrite, // MX
Txt_StringWrite, // TXT
Minfo_StringWrite, // RP
Mx_StringWrite, // AFSDB
Txt_StringWrite, // X25
Txt_StringWrite, // ISDN
Mx_StringWrite, // RT
NULL, // NSAP
NULL, // NSAPPTR
NULL, // SIG
NULL, // KEY
NULL, // PX
NULL, // GPOS
Aaaa_StringWrite, // AAAA
NULL, // LOC
NULL, // NXT
NULL, // EID
NULL, // NIMLOC
Srv_StringWrite, // SRV
NULL, // 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)
// note these follow, but require OFFSET_TO_WINS_RR subtraction
// from actual type value
NULL, // WINS
NULL // WINS-R
};
//
// Record to string functions.
//
DNS_STATUS Dns_WriteRecordToString( OUT PCHAR pBuffer, IN DWORD BufferLength, IN PDNS_RECORD pRecord, IN DNS_CHARSET CharSet, IN DWORD Flags ) /*++
Routine Description:
Write record to string.
Arguments:
pBuffer -- string buffer to write to
BufferLength -- buffer length (bytes)
pRecord -- record to print
CharSet -- char set for string
Flags -- flags
Return Value:
NO_ERROR if successful. ErrorCode on failure: ERROR_INSUFFICIENT_BUFFER -- buffer too small. ERROR_INVALID_DATA -- bad record.
--*/ { DNS_STATUS status = NO_ERROR; PCHAR pch = pBuffer; PCHAR pend = pBuffer + BufferLength; WORD type = pRecord->wType; DWORD index; CHAR typeNameBuf[ MAX_RECORD_NAME_LENGTH+1 ]; STR_WRITE_CONTEXT context;
//
// validity check
//
if ( !pRecord ) { return ERROR_INVALID_DATA; }
//
// DCR: currently can only write narrow char set record strings
//
if ( CharSet == DnsCharSetUnicode ) { return ERROR_INVALID_DATA; }
// setup context
RtlZeroMemory( &context, sizeof(context) ); context.pRecord = pRecord; context.Flags = Flags; context.CharSet = CharSet;
//
// print record name
//
pch = WriteRecordDataNameToString( pch, pend, pRecord->pName, & context );
//
// write record type
//
if ( !pch || pend-pch < MAX_RECORD_NAME_LENGTH+1 ) { status = ERROR_INSUFFICIENT_BUFFER; goto Done; } Dns_WriteStringForType_A( typeNameBuf, type ); pch += sprintf( pch, " %s ", typeNameBuf );
//
// write no-exist record?
//
if ( !pRecord->wDataLength ) { if ( pend-pch < MAX_RECORD_NAME_LENGTH+1 ) { status = ERROR_INSUFFICIENT_BUFFER; goto Done; } pch += sprintf( pch, "NOEXIST" ); status = NO_ERROR; goto Done; }
//
// write data
//
index = INDEX_FOR_TYPE( type ); DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
if ( index && RR_StringWriteTable[index] ) { pch = RR_StringWriteTable[index]( pRecord, pch, pend, & context ); if ( !pch ) { //status = GetLastError();
status = ERROR_INSUFFICIENT_BUFFER; } } else //if ( !index )
{ // DCR: could do an unknown type print
status = ERROR_INVALID_DATA; goto Done; }
Done:
DNSDBG( WRITE, ( "Leaving Dns_WriteRecordToString() => %d\n" "\tstring = %s\n", status, (status == NO_ERROR) ? pBuffer : "" ));
return status; }
PDNS_RECORD Dns_CreateRecordFromString( IN PSTR pString, IN DNS_CHARSET CharSet, IN DWORD Flags ) /*++
Routine Description:
Create record from string.
Arguments:
pString -- record string to parse
CharSet -- char set of result
Flags -- flags
Return Value:
Ptr to record if successful. Null on failure. GetLastError() returns error.
--*/ { SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); return NULL; }
//
// End rrstrw.c
//
|