dnsapi: Implement DnsExtractRecordsFromMessage().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-11-02 12:48:15 +01:00
parent 87f94202bb
commit aec19e86f6
3 changed files with 632 additions and 26 deletions

View File

@ -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.@]
*

View File

@ -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;
}

View File

@ -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();
}