You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
866 lines
17 KiB
866 lines
17 KiB
/*++
|
|
|
|
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
|
|
//
|
|
|
|
|