dnsapi: Implement DnsExtractRecordsFromMessage().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
87f94202bb
commit
aec19e86f6
|
@ -150,32 +150,6 @@ VOID WINAPI DnsReleaseContextHandle( HANDLE context )
|
|||
FIXME( "(%p) stub\n", context );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsExtractRecordsFromMessage_UTF8 [DNSAPI.@]
|
||||
*
|
||||
*/
|
||||
DNS_STATUS WINAPI DnsExtractRecordsFromMessage_UTF8( PDNS_MESSAGE_BUFFER buffer,
|
||||
WORD len, PDNS_RECORDA *record )
|
||||
{
|
||||
FIXME( "(%p,%d,%p) stub\n", buffer, len, record );
|
||||
|
||||
*record = NULL;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsExtractRecordsFromMessage_W [DNSAPI.@]
|
||||
*
|
||||
*/
|
||||
DNS_STATUS WINAPI DnsExtractRecordsFromMessage_W( PDNS_MESSAGE_BUFFER buffer,
|
||||
WORD len, PDNS_RECORDW *record )
|
||||
{
|
||||
FIXME( "(%p,%d,%p) stub\n", buffer, len, record );
|
||||
|
||||
*record = NULL;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsModifyRecordsInSet_A [DNSAPI.@]
|
||||
*
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* DNS support
|
||||
*
|
||||
* Copyright (C) 2006 Hans Leidekker
|
||||
* Copyright (C) 2021 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -95,6 +96,18 @@ const char *debugstr_type( unsigned short type )
|
|||
}
|
||||
}
|
||||
|
||||
static const char *debugstr_section( DNS_SECTION section )
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case DnsSectionQuestion: return "Question";
|
||||
case DnsSectionAnswer: return "Answer";
|
||||
case DnsSectionAuthority: return "Authority";
|
||||
case DnsSectionAddtional: return "Additional";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
static int strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
|
||||
{
|
||||
if (wide)
|
||||
|
@ -103,6 +116,95 @@ static int strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
|
|||
return lstrcmpiA( str1, str2 );
|
||||
}
|
||||
|
||||
static WORD get_word( const BYTE **ptr )
|
||||
{
|
||||
WORD ret = ((*ptr)[0] << 8) + (*ptr)[1];
|
||||
*ptr += sizeof(WORD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD get_dword( const BYTE **ptr )
|
||||
{
|
||||
DWORD ret = ((*ptr)[0] << 24) + ((*ptr)[1] << 16) + ((*ptr)[2] << 8) + (*ptr)[3];
|
||||
*ptr += sizeof(DWORD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const BYTE *skip_name( const BYTE *ptr, const BYTE *end )
|
||||
{
|
||||
BYTE len;
|
||||
|
||||
while (ptr < end && (len = *ptr++))
|
||||
{
|
||||
switch (len & 0xc0)
|
||||
{
|
||||
case 0:
|
||||
ptr += len;
|
||||
continue;
|
||||
case 0xc0:
|
||||
ptr++;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ptr < end) return ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const BYTE *skip_record( const BYTE *ptr, const BYTE *end, DNS_SECTION section )
|
||||
{
|
||||
WORD len;
|
||||
|
||||
if (!(ptr = skip_name( ptr, end ))) return NULL;
|
||||
ptr += 2; /* type */
|
||||
ptr += 2; /* class */
|
||||
if (section != DnsSectionQuestion)
|
||||
{
|
||||
ptr += 4; /* ttl */
|
||||
if (ptr + 2 > end) return NULL;
|
||||
len = get_word( &ptr );
|
||||
ptr += len;
|
||||
}
|
||||
if (ptr > end) return NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static const BYTE *get_name( const BYTE *base, const BYTE *end, const BYTE *ptr,
|
||||
char name[DNS_MAX_NAME_BUFFER_LENGTH] )
|
||||
{
|
||||
BYTE len;
|
||||
char *out = name;
|
||||
const BYTE *next = NULL;
|
||||
int loop = 0;
|
||||
|
||||
while (ptr < end && (len = *ptr++))
|
||||
{
|
||||
switch (len & 0xc0)
|
||||
{
|
||||
case 0:
|
||||
if (out + len + 1 >= name + DNS_MAX_NAME_BUFFER_LENGTH) return NULL;
|
||||
if (out > name) *out++ = '.';
|
||||
memcpy( out, ptr, len );
|
||||
out += len;
|
||||
ptr += len;
|
||||
continue;
|
||||
case 0xc0:
|
||||
if (!next) next = ptr + 1;
|
||||
if (++loop >= end - base) return NULL;
|
||||
if (ptr < end) ptr = base + ((len & 0x3f) << 8) + *ptr;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (ptr >= end) return NULL;
|
||||
if (out == name) *out++ = '.';
|
||||
*out = 0;
|
||||
return next ? next : ptr;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsRecordCompare [DNSAPI.@]
|
||||
*
|
||||
|
@ -786,3 +888,334 @@ PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int get_record_size( WORD type, const BYTE *data, WORD len )
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DNS_TYPE_KEY:
|
||||
return offsetof( DNS_RECORDA, Data.Key.Key[len] );
|
||||
|
||||
case DNS_TYPE_SIG:
|
||||
return offsetof( DNS_RECORDA, Data.Sig.Signature[len] );
|
||||
|
||||
case DNS_TYPE_HINFO:
|
||||
case DNS_TYPE_ISDN:
|
||||
case DNS_TYPE_TEXT:
|
||||
case DNS_TYPE_X25:
|
||||
{
|
||||
int i;
|
||||
const BYTE *pos = data;
|
||||
for (i = 0; pos < data + len; i++) pos += pos[0] + 1;
|
||||
return offsetof( DNS_RECORDA, Data.Txt.pStringArray[i] );
|
||||
}
|
||||
|
||||
case DNS_TYPE_NULL:
|
||||
case DNS_TYPE_OPT:
|
||||
return offsetof( DNS_RECORDA, Data.Null.Data[len] );
|
||||
|
||||
case DNS_TYPE_WKS:
|
||||
return offsetof( DNS_RECORDA, Data.Wks.BitMask[len / 8] );
|
||||
|
||||
case DNS_TYPE_NXT:
|
||||
return offsetof( DNS_RECORDA, Data.Nxt.wTypes[len * 8] );
|
||||
|
||||
case DNS_TYPE_WINS:
|
||||
return offsetof( DNS_RECORDA, Data.Wins.WinsServers[len / 4] );
|
||||
|
||||
default:
|
||||
return sizeof(DNS_RECORDA);
|
||||
}
|
||||
}
|
||||
|
||||
static DNS_STATUS extract_rdata( const BYTE *base, const BYTE *end, const BYTE *pos, WORD len, WORD type,
|
||||
DNS_RECORDA *r )
|
||||
{
|
||||
DNS_CHARSET in = DnsCharSetUtf8, out = r->Flags.S.CharSet;
|
||||
char name[DNS_MAX_NAME_BUFFER_LENGTH];
|
||||
DNS_STATUS ret = ERROR_SUCCESS;
|
||||
const BYTE *rrend = pos + len;
|
||||
unsigned int i;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DNS_TYPE_A:
|
||||
if (pos + sizeof(DWORD) > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.A.IpAddress = *(const DWORD *)pos;
|
||||
r->wDataLength = sizeof(DNS_A_DATA);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_AAAA:
|
||||
if (pos + sizeof(IP6_ADDRESS) > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
|
||||
{
|
||||
r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
|
||||
pos += sizeof(DWORD);
|
||||
}
|
||||
r->wDataLength = sizeof(DNS_AAAA_DATA);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_KEY:
|
||||
if (pos + 4 > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.KEY.wFlags = get_word( &pos );
|
||||
r->Data.KEY.chProtocol = *pos++;
|
||||
r->Data.KEY.chAlgorithm = *pos++;
|
||||
r->Data.KEY.wKeyLength = rrend - pos;
|
||||
memcpy( r->Data.KEY.Key, pos, r->Data.KEY.wKeyLength );
|
||||
r->wDataLength = offsetof( DNS_KEY_DATA, Key[r->Data.KEY.wKeyLength] );
|
||||
break;
|
||||
|
||||
case DNS_TYPE_RP:
|
||||
case DNS_TYPE_MINFO:
|
||||
if (!(pos = get_name( base, end, pos, name ))) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.MINFO.pNameMailbox = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
if (!get_name( base, end, pos, name )) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.MINFO.pNameErrorsMailbox = strcpyX( name, in, out )))
|
||||
{
|
||||
heap_free( r->Data.MINFO.pNameMailbox );
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
r->wDataLength = sizeof(DNS_MINFO_DATAA);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_AFSDB:
|
||||
case DNS_TYPE_RT:
|
||||
case DNS_TYPE_MX:
|
||||
if (pos + sizeof(WORD) > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.MX.wPreference = get_word( &pos );
|
||||
if (!get_name( base, end, pos, name )) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.MX.pNameExchange = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
r->wDataLength = sizeof(DNS_MX_DATAA) + sizeof(DWORD);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_NULL:
|
||||
r->Data.Null.dwByteCount = len;
|
||||
memcpy( r->Data.Null.Data, pos, len );
|
||||
r->wDataLength = offsetof( DNS_NULL_DATA, Data[len] );
|
||||
break;
|
||||
|
||||
case DNS_TYPE_OPT:
|
||||
r->Data.OPT.wDataLength = len;
|
||||
r->Data.OPT.wPad = 0;
|
||||
memcpy( r->Data.OPT.Data, pos, len );
|
||||
r->wDataLength = offsetof( DNS_OPT_DATA, Data[len] );
|
||||
break;
|
||||
|
||||
case DNS_TYPE_CNAME:
|
||||
case DNS_TYPE_NS:
|
||||
case DNS_TYPE_MB:
|
||||
case DNS_TYPE_MD:
|
||||
case DNS_TYPE_MF:
|
||||
case DNS_TYPE_MG:
|
||||
case DNS_TYPE_MR:
|
||||
case DNS_TYPE_PTR:
|
||||
if (!get_name( base, end, pos, name )) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.PTR.pNameHost = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
r->wDataLength = sizeof(DNS_PTR_DATAA) + sizeof(DWORD);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_SIG:
|
||||
if (pos + 18 > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.SIG.wTypeCovered = get_word( &pos );
|
||||
r->Data.SIG.chAlgorithm = *pos++;
|
||||
r->Data.SIG.chLabelCount = *pos++;
|
||||
r->Data.SIG.dwOriginalTtl = get_dword( &pos );
|
||||
r->Data.SIG.dwExpiration = get_dword( &pos );
|
||||
r->Data.SIG.dwTimeSigned = get_dword( &pos );
|
||||
r->Data.SIG.wKeyTag = get_word( &pos );
|
||||
if (!(pos = get_name( base, end, pos, name ))) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.SIG.pNameSigner = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
r->Data.SIG.wSignatureLength = rrend - pos;
|
||||
memcpy( r->Data.SIG.Signature, pos, r->Data.SIG.wSignatureLength );
|
||||
r->wDataLength = offsetof( DNS_SIG_DATAA, Signature[r->Data.SIG.wSignatureLength] );
|
||||
break;
|
||||
|
||||
case DNS_TYPE_SOA:
|
||||
if (!(pos = get_name( base, end, pos, name ))) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.SOA.pNamePrimaryServer = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
if (!(pos = get_name( base, end, pos, name ))) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.SOA.pNameAdministrator = strcpyX( name, in, out )))
|
||||
{
|
||||
heap_free( r->Data.SOA.pNamePrimaryServer );
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
if (pos + 5 * sizeof(DWORD) > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.SOA.dwSerialNo = get_dword( &pos );
|
||||
r->Data.SOA.dwRefresh = get_dword( &pos );
|
||||
r->Data.SOA.dwRetry = get_dword( &pos );
|
||||
r->Data.SOA.dwExpire = get_dword( &pos );
|
||||
r->Data.SOA.dwDefaultTtl = get_dword( &pos );
|
||||
r->wDataLength = sizeof(DNS_SOA_DATAA);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_SRV:
|
||||
if (pos + 3 * sizeof(WORD) > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
r->Data.SRV.wPriority = get_word( &pos );
|
||||
r->Data.SRV.wWeight = get_word( &pos );
|
||||
r->Data.SRV.wPort = get_word( &pos );
|
||||
if (!get_name( base, end, pos, name )) return DNS_ERROR_BAD_PACKET;
|
||||
if (!(r->Data.SRV.pNameTarget = strcpyX( name, in, out ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
r->wDataLength = sizeof(DNS_SRV_DATAA);
|
||||
break;
|
||||
|
||||
case DNS_TYPE_HINFO:
|
||||
case DNS_TYPE_ISDN:
|
||||
case DNS_TYPE_X25:
|
||||
case DNS_TYPE_TEXT:
|
||||
for (i = 0; pos < rrend; i++)
|
||||
{
|
||||
BYTE len = pos[0];
|
||||
if (pos + len + 1 > rrend) return DNS_ERROR_BAD_PACKET;
|
||||
memcpy( name, pos + 1, len );
|
||||
name[len] = 0;
|
||||
if (!(r->Data.TXT.pStringArray[i] = strcpyX( name, in, out )))
|
||||
{
|
||||
while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
pos += len + 1;
|
||||
}
|
||||
r->Data.TXT.dwStringCount = i;
|
||||
r->wDataLength = offsetof( DNS_TXT_DATAA, pStringArray[r->Data.TXT.dwStringCount] );
|
||||
break;
|
||||
|
||||
case DNS_TYPE_ATMA:
|
||||
case DNS_TYPE_LOC:
|
||||
case DNS_TYPE_NXT:
|
||||
case DNS_TYPE_TSIG:
|
||||
case DNS_TYPE_WKS:
|
||||
case DNS_TYPE_TKEY:
|
||||
case DNS_TYPE_WINS:
|
||||
case DNS_TYPE_WINSR:
|
||||
default:
|
||||
FIXME( "unhandled type: %s\n", debugstr_type( type ));
|
||||
return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DNS_STATUS extract_record( const DNS_MESSAGE_BUFFER *hdr, const BYTE *end, const BYTE **pos,
|
||||
DNS_SECTION section, DNS_CHARSET charset, DNS_RECORDA **recp )
|
||||
{
|
||||
DNS_STATUS ret;
|
||||
DNS_RECORDA *record;
|
||||
char name[DNS_MAX_NAME_BUFFER_LENGTH];
|
||||
WORD type, rdlen;
|
||||
DWORD ttl;
|
||||
const BYTE *base = (const BYTE *)hdr;
|
||||
const BYTE *ptr = *pos;
|
||||
|
||||
if (!(ptr = get_name( base, end, ptr, name ))) return DNS_ERROR_BAD_PACKET;
|
||||
|
||||
if (ptr + 10 > end) return DNS_ERROR_BAD_PACKET;
|
||||
type = get_word( &ptr );
|
||||
ptr += sizeof(WORD); /* class */
|
||||
ttl = get_dword( &ptr );
|
||||
rdlen = get_word( &ptr );
|
||||
if (ptr + rdlen > end) return DNS_ERROR_BAD_PACKET;
|
||||
*pos = ptr + rdlen;
|
||||
|
||||
if (!(record = heap_alloc_zero( get_record_size( type, ptr, rdlen ) ))) return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
record->wType = type;
|
||||
record->Flags.S.Section = section;
|
||||
record->Flags.S.CharSet = charset;
|
||||
record->dwTtl = ttl;
|
||||
|
||||
if (!(record->pName = strcpyX( name, DnsCharSetUtf8, charset )))
|
||||
{
|
||||
heap_free( record );
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
if ((ret = extract_rdata( base, end, ptr, rdlen, type, record )))
|
||||
{
|
||||
heap_free( record->pName );
|
||||
heap_free( record );
|
||||
return ret;
|
||||
}
|
||||
*recp = record;
|
||||
TRACE( "found %s record in %s section\n", debugstr_type( record->wType ), debugstr_section( section ) );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DNS_STATUS extract_message_records( const DNS_MESSAGE_BUFFER *buffer, WORD len, DNS_CHARSET charset,
|
||||
DNS_RRSET *rrset )
|
||||
{
|
||||
DNS_STATUS ret = ERROR_SUCCESS;
|
||||
const DNS_HEADER *hdr = &buffer->MessageHead;
|
||||
DNS_RECORDA *record;
|
||||
const BYTE *base = (const BYTE *)hdr;
|
||||
const BYTE *end = base + len;
|
||||
const BYTE *ptr = (const BYTE *)buffer->MessageBody;
|
||||
unsigned int num;
|
||||
|
||||
if (hdr->IsResponse && !hdr->AnswerCount) return DNS_ERROR_BAD_PACKET;
|
||||
|
||||
for (num = 0; num < hdr->QuestionCount; num++)
|
||||
if (!(ptr = skip_record( ptr, end, DnsSectionQuestion ))) return DNS_ERROR_BAD_PACKET;
|
||||
|
||||
for (num = 0; num < hdr->AnswerCount; num++)
|
||||
{
|
||||
if ((ret = extract_record( buffer, end, &ptr, DnsSectionAnswer, charset, &record )))
|
||||
return ret;
|
||||
DNS_RRSET_ADD( *rrset, (DNS_RECORD *)record );
|
||||
}
|
||||
|
||||
for (num = 0; num < hdr->NameServerCount; num++)
|
||||
if (!(ptr = skip_record( ptr, end, DnsSectionAuthority ))) return DNS_ERROR_BAD_PACKET;
|
||||
|
||||
for (num = 0; num < hdr->AdditionalCount; num++)
|
||||
{
|
||||
if ((ret = extract_record( buffer, end, &ptr, DnsSectionAddtional, charset, &record ))) return ret;
|
||||
DNS_RRSET_ADD( *rrset, (DNS_RECORD *)record );
|
||||
}
|
||||
|
||||
if (ptr != end) ret = DNS_ERROR_BAD_PACKET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsExtractRecordsFromMessage_UTF8 [DNSAPI.@]
|
||||
*
|
||||
*/
|
||||
DNS_STATUS WINAPI DnsExtractRecordsFromMessage_UTF8( DNS_MESSAGE_BUFFER *buffer, WORD len,
|
||||
DNS_RECORDA **result )
|
||||
{
|
||||
DNS_STATUS ret = DNS_ERROR_BAD_PACKET;
|
||||
DNS_RRSET rrset;
|
||||
|
||||
if (len < sizeof(*buffer)) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
DNS_RRSET_INIT( rrset );
|
||||
ret = extract_message_records( buffer, len, DnsCharSetUtf8, &rrset );
|
||||
DNS_RRSET_TERMINATE( rrset );
|
||||
|
||||
if (!ret) *result = (DNS_RECORDA *)rrset.pFirstRR;
|
||||
else DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DnsExtractRecordsFromMessage_W [DNSAPI.@]
|
||||
*
|
||||
*/
|
||||
DNS_STATUS WINAPI DnsExtractRecordsFromMessage_W( DNS_MESSAGE_BUFFER *buffer, WORD len,
|
||||
DNS_RECORDW **result )
|
||||
{
|
||||
DNS_STATUS ret = DNS_ERROR_BAD_PACKET;
|
||||
DNS_RRSET rrset;
|
||||
|
||||
if (len < sizeof(*buffer)) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
DNS_RRSET_INIT( rrset );
|
||||
ret = extract_message_records( buffer, len, DnsCharSetUnicode, &rrset );
|
||||
DNS_RRSET_TERMINATE( rrset );
|
||||
|
||||
if (!ret) *result = (DNS_RECORDW *)rrset.pFirstRR;
|
||||
else DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -138,9 +138,208 @@ static void test_DnsRecordSetDetach( void )
|
|||
ok( !r2.pNext, "failed unexpectedly\n" );
|
||||
}
|
||||
|
||||
static BYTE msg_empty[] = /* empty message */
|
||||
{
|
||||
0x12, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
static BYTE msg_empty_answer[] = /* marked as answer but contains only question */
|
||||
{
|
||||
0x12, 0x34, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01
|
||||
};
|
||||
static BYTE msg_question[] = /* question only */
|
||||
{
|
||||
0x12, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01
|
||||
};
|
||||
static BYTE msg_winehq[] = /* valid answer for winehq.org */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 'w', 'i', 'n', 'e', 'h', 'q', 0x03, 'o', 'r', 'g', 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x04, 0x04, 0x04, 0x51, 0x7c
|
||||
};
|
||||
static BYTE msg_invchars[] = /* invalid characters in name */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 'a', '$', 0x02, 'b', '\\', 0x02, 'c', '.', 0x02, 0x09, 'd', 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x04, 0x04, 0x51, 0x7c
|
||||
};
|
||||
static BYTE msg_root[] = /* root name */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x04, 0x04, 0x51, 0x7c
|
||||
};
|
||||
static BYTE msg_label[] = /* name with binary label, not supported on Windows */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 'a', 'b', 'c', 0x41, 0x01, 0x34, 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x04, 0x04, 0x51, 0x7c
|
||||
};
|
||||
static BYTE msg_loop[] = /* name with loop */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01,
|
||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x04, 0x04, 0x51, 0x7c
|
||||
};
|
||||
static BYTE msg_types[] = /* various record types */
|
||||
{
|
||||
0x12, 0x34, 0x81, 0x80, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 'w', 'i', 'n', 'e', 'h', 'q', 0x03, 'o', 'r', 'g', 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
/* CNAME */ 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x05, 0x01, 'a', 0x01, 'b', 0x00,
|
||||
/* MX */ 0xc0, 0x0c, 0x00, 0x0f, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x07, 0x03, 0x04, 0x01, 'c', 0x01, 'd', 0x00,
|
||||
/* AAAA */ 0xc0, 0x0c, 0x00, 0x1c, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
|
||||
/* KEY */ 0xc0, 0x0c, 0x00, 0x19, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x06, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
|
||||
/* TXT */ 0x01, 't', 0x01, 'x', 0x00, 0x00, 0x10, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x00, 0x09, 0x02, 'z', 'y', 0x00, 0x04, 'X', 'Y', 0xc3, 0xa9
|
||||
};
|
||||
|
||||
static void test_DnsExtractRecordsFromMessage(void)
|
||||
{
|
||||
DNS_STATUS ret;
|
||||
DNS_RECORDA *rec, *r;
|
||||
DNS_RECORDW *recW, *rW;
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_empty, sizeof(msg_empty) - 1, &rec );
|
||||
ok( ret == ERROR_INVALID_PARAMETER || broken(ret == DNS_ERROR_BAD_PACKET) /* win7 */,
|
||||
"failed %u\n", ret );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_empty, sizeof(msg_empty), &rec );
|
||||
ok( ret == DNS_ERROR_BAD_PACKET, "failed %u\n", ret );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_empty_answer, sizeof(msg_empty_answer), &rec );
|
||||
ok( ret == DNS_ERROR_BAD_PACKET, "failed %u\n", ret );
|
||||
|
||||
rec = (void *)0xdeadbeef;
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_question, sizeof(msg_question), &rec );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
ok( !rec, "record %p\n", rec );
|
||||
|
||||
rec = (void *)0xdeadbeef;
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_winehq, sizeof(msg_winehq), &rec );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
ok( rec != NULL, "record not set\n" );
|
||||
ok( !strcmp( rec->pName, "winehq.org" ), "wrong name %s\n", rec->pName );
|
||||
ok( rec->Flags.S.Section == DnsSectionAnswer, "wrong section %u\n", rec->Flags.S.Section );
|
||||
ok( rec->Flags.S.CharSet == DnsCharSetUtf8, "wrong charset %u\n", rec->Flags.S.CharSet );
|
||||
ok( rec->wType == DNS_TYPE_A, "wrong type %u\n", rec->wType );
|
||||
ok( rec->wDataLength == sizeof(DNS_A_DATA), "wrong len %u\n", rec->wDataLength );
|
||||
ok( rec->dwTtl == 0x04050607, "wrong ttl %x\n", rec->dwTtl );
|
||||
ok( rec->Data.A.IpAddress == 0x7c510404, "wrong addr %08x\n", rec->Data.A.IpAddress );
|
||||
ok( !rec->pNext, "next record %p\n", rec->pNext );
|
||||
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
|
||||
|
||||
recW = (void *)0xdeadbeef;
|
||||
ret = DnsExtractRecordsFromMessage_W( (DNS_MESSAGE_BUFFER *)msg_winehq, sizeof(msg_winehq), &recW );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
ok( recW != NULL, "record not set\n" );
|
||||
ok( !wcscmp( recW->pName, L"winehq.org" ), "wrong name %s\n", debugstr_w(recW->pName) );
|
||||
DnsRecordListFree( (DNS_RECORD *)recW, DnsFreeRecordList );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_invchars, sizeof(msg_invchars), &rec );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
ok( !strcmp( rec->pName, "a$.b\\.c..\td" ), "wrong name %s\n", rec->pName );
|
||||
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_root, sizeof(msg_root), &rec );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
ok( !strcmp( rec->pName, "." ), "wrong name %s\n", rec->pName );
|
||||
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_label, sizeof(msg_label), &rec );
|
||||
ok( ret == DNS_ERROR_BAD_PACKET, "failed %u\n", ret );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_loop, sizeof(msg_loop), &rec );
|
||||
ok( ret == DNS_ERROR_BAD_PACKET, "failed %u\n", ret );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_UTF8( (DNS_MESSAGE_BUFFER *)msg_types, sizeof(msg_types), &rec );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
r = rec;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !strcmp( r->pName, "winehq.org" ), "wrong name %s\n", r->pName );
|
||||
ok( r->wType == DNS_TYPE_CNAME, "wrong type %u\n", r->wType );
|
||||
ok( !strcmp( r->Data.CNAME.pNameHost, "a.b" ), "wrong cname %s\n", r->Data.CNAME.pNameHost );
|
||||
ok( r->wDataLength == sizeof(DNS_PTR_DATAA) + 4, "wrong len %x\n", r->wDataLength );
|
||||
r = r->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !strcmp( r->pName, "winehq.org" ), "wrong name %s\n", r->pName );
|
||||
ok( r->wType == DNS_TYPE_MX, "wrong type %u\n", r->wType );
|
||||
ok( r->Data.MX.wPreference == 0x0304, "wrong pref %x\n", r->Data.MX.wPreference );
|
||||
ok( !strcmp( r->Data.MX.pNameExchange, "c.d" ), "wrong mx %s\n", r->Data.MX.pNameExchange );
|
||||
ok( r->wDataLength == sizeof(DNS_MX_DATAA) + 4, "wrong len %x\n", r->wDataLength );
|
||||
r = r->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !strcmp( r->pName, "winehq.org" ), "wrong name %s\n", r->pName );
|
||||
ok( r->wType == DNS_TYPE_AAAA, "wrong type %u\n", r->wType );
|
||||
ok( r->Data.AAAA.Ip6Address.IP6Dword[0] == 0x04030201, "wrong addr %x\n",
|
||||
r->Data.AAAA.Ip6Address.IP6Dword[0] );
|
||||
ok( r->Data.AAAA.Ip6Address.IP6Dword[1] == 0x08070605, "wrong addr %x\n",
|
||||
r->Data.AAAA.Ip6Address.IP6Dword[1] );
|
||||
ok( r->Data.AAAA.Ip6Address.IP6Dword[2] == 0x0c0b0a09, "wrong addr %x\n",
|
||||
r->Data.AAAA.Ip6Address.IP6Dword[2] );
|
||||
ok( r->Data.AAAA.Ip6Address.IP6Dword[3] == 0x000f0e0d, "wrong addr %x\n",
|
||||
r->Data.AAAA.Ip6Address.IP6Dword[3] );
|
||||
ok( r->wDataLength == sizeof(DNS_AAAA_DATA), "wrong len %x\n", r->wDataLength );
|
||||
r = r->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !strcmp( r->pName, "winehq.org" ), "wrong name %s\n", r->pName );
|
||||
ok( r->wType == DNS_TYPE_KEY, "wrong type %u\n", r->wType );
|
||||
ok( r->Data.KEY.wFlags == 0x1122, "wrong flags %x\n", r->Data.KEY.wFlags );
|
||||
ok( r->Data.KEY.chProtocol == 0x33, "wrong protocol %x\n", r->Data.KEY.chProtocol );
|
||||
ok( r->Data.KEY.chAlgorithm == 0x44, "wrong algorithm %x\n", r->Data.KEY.chAlgorithm );
|
||||
ok( r->Data.KEY.wKeyLength == 0x02, "wrong len %x\n", r->Data.KEY.wKeyLength );
|
||||
ok( r->Data.KEY.Key[0] == 0x55, "wrong key %x\n", r->Data.KEY.Key[0] );
|
||||
ok( r->Data.KEY.Key[1] == 0x66, "wrong key %x\n", r->Data.KEY.Key[1] );
|
||||
ok( r->wDataLength == offsetof( DNS_KEY_DATA, Key[r->Data.KEY.wKeyLength] ),
|
||||
"wrong len %x\n", r->wDataLength );
|
||||
r = r->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !strcmp( r->pName, "t.x" ), "wrong name %s\n", r->pName );
|
||||
ok( r->wType == DNS_TYPE_TEXT, "wrong type %u\n", r->wType );
|
||||
ok( r->Data.TXT.dwStringCount == 3, "wrong count %u\n", r->Data.TXT.dwStringCount );
|
||||
ok( !strcmp( r->Data.TXT.pStringArray[0], "zy" ), "wrong string %s\n", r->Data.TXT.pStringArray[0] );
|
||||
ok( !strcmp( r->Data.TXT.pStringArray[1], "" ), "wrong string %s\n", r->Data.TXT.pStringArray[1] );
|
||||
ok( !strcmp( r->Data.TXT.pStringArray[2], "XY\xc3\xa9" ), "wrong string %s\n", r->Data.TXT.pStringArray[2] );
|
||||
ok( r->wDataLength == offsetof( DNS_TXT_DATAA, pStringArray[r->Data.TXT.dwStringCount] ),
|
||||
"wrong len %x\n", r->wDataLength );
|
||||
ok( !r->pNext, "next record %p\n", r->pNext );
|
||||
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
|
||||
|
||||
ret = DnsExtractRecordsFromMessage_W( (DNS_MESSAGE_BUFFER *)msg_types, sizeof(msg_types), &recW );
|
||||
ok( !ret, "failed %u\n", ret );
|
||||
rW = recW;
|
||||
ok( rW != NULL, "record not set\n" );
|
||||
ok( !wcscmp( rW->pName, L"winehq.org" ), "wrong name %s\n", debugstr_w(rW->pName) );
|
||||
ok( rW->wType == DNS_TYPE_CNAME, "wrong type %u\n", rW->wType );
|
||||
ok( !wcscmp( rW->Data.CNAME.pNameHost, L"a.b" ), "wrong cname %s\n", debugstr_w(rW->Data.CNAME.pNameHost) );
|
||||
rW = rW->pNext;
|
||||
ok( rW != NULL, "record not set\n" );
|
||||
ok( !wcscmp( rW->pName, L"winehq.org" ), "wrong name %s\n", debugstr_w(rW->pName) );
|
||||
ok( rW->wType == DNS_TYPE_MX, "wrong type %u\n", rW->wType );
|
||||
ok( !wcscmp( rW->Data.MX.pNameExchange, L"c.d" ), "wrong mx %s\n", debugstr_w(rW->Data.MX.pNameExchange) );
|
||||
rW = rW->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !wcscmp( rW->pName, L"winehq.org" ), "wrong name %s\n", debugstr_w(rW->pName) );
|
||||
ok( rW->wType == DNS_TYPE_AAAA, "wrong type %u\n", rW->wType );
|
||||
rW = rW->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !wcscmp( rW->pName, L"winehq.org" ), "wrong name %s\n", debugstr_w(rW->pName) );
|
||||
rW = rW->pNext;
|
||||
ok( r != NULL, "record not set\n" );
|
||||
ok( !wcscmp( rW->pName, L"t.x" ), "wrong name %s\n", debugstr_w(rW->pName) );
|
||||
ok( rW->wType == DNS_TYPE_TEXT, "wrong type %u\n", rW->wType );
|
||||
ok( rW->Data.TXT.dwStringCount == 3, "wrong count %u\n", rW->Data.TXT.dwStringCount );
|
||||
ok( !wcscmp( rW->Data.TXT.pStringArray[0], L"zy" ), "wrong string %s\n", debugstr_w(rW->Data.TXT.pStringArray[0]) );
|
||||
ok( !wcscmp( rW->Data.TXT.pStringArray[1], L"" ), "wrong string %s\n", debugstr_w(rW->Data.TXT.pStringArray[1]) );
|
||||
ok( !wcscmp( rW->Data.TXT.pStringArray[2], L"XY\x00e9" ), "wrong string %s\n", debugstr_w(rW->Data.TXT.pStringArray[2]) );
|
||||
ok( !rW->pNext, "next record %p\n", rW->pNext );
|
||||
DnsRecordListFree( (DNS_RECORD *)recW, DnsFreeRecordList );
|
||||
}
|
||||
|
||||
START_TEST(record)
|
||||
{
|
||||
test_DnsRecordCompare();
|
||||
test_DnsRecordSetCompare();
|
||||
test_DnsRecordSetDetach();
|
||||
test_DnsExtractRecordsFromMessage();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue