Partager via


DnsQueryRaw, fonction (windns.h)

Important

Certaines informations se rapportent à un produit de préversion qui peut être considérablement modifié avant sa commercialisation. Microsoft exclut toute garantie, expresse ou implicite, concernant les informations fournies ici.

Vous permet d’effectuer une requête DNS qui accepte un paquet brut contenant une requête DNS, ou un nom et un type de requête. Vous pouvez augmenter la requête avec les paramètres et la configuration du système hôte.

  • Vous pouvez appliquer de nouvelles options de requête et des serveurs personnalisés à un paquet de requête DNS brut déjà mis en forme.
  • Vous pouvez également fournir un nom et un type de requête, et recevoir les enregistrements analysés et le paquet de résultat brut (ce qui permet aux clients d’interagir avec toutes les informations reçues du serveur).

Les requêtes sont effectuées de manière asynchrone ; et les résultats sont transmis à une fonction de rappel asynchrone DNS_QUERY_RAW_COMPLETION_ROUTINE que vous implémentez. Pour annuler une requête, appelez DnsCancelQueryRaw.

Syntaxe

DNS_STATUS DnsQueryRaw(
  DNS_QUERY_RAW_REQUEST *queryRequest,
  DNS_QUERY_RAW_CANCEL  *cancelHandle
);

Paramètres

queryRequest

Type : _In_ DNS_QUERY_RAW_REQUEST*

Demande de requête.

cancelHandle

Type : _Inout_ DNS_QUERY_RAW_CANCEL*

Permet d’obtenir un handle d’annulation, que vous pouvez passer à DnsCancelQueryRaw si vous devez annuler la requête.

Valeur retournée

Valeur DNS_STATUS indiquant la réussite ou l’échec. Si DNS_REQUEST_PENDING est retourné, une fois la requête terminée, le système appelle l’implémentation DNS_QUERY_RAW_COMPLETION_ROUTINE que vous avez passée dans le membre queryCompletionCallback de queryRequest. Ce rappel recevra les résultats de la requête en cas de réussite, ou d’échecs ou d’annulations.

Remarques

La structure d’un paquet brut est la représentation filaire de la requête et de la réponse DNS, comme documenté par RFC 1035. Un en-tête DNS de 12 octets est suivi d’une section de question pour la requête ou d’un nombre variable (pouvant être égal à 0) d’enregistrements pour la réponse. Si TCP est utilisé, le paquet brut doit être précédé d’un champ de longueur de 2 octets. Vous pouvez utiliser cette API pour appliquer des règles NRPT de l’hôte ou pour effectuer des requêtes DNS chiffrées, entre autres choses.

Exemples

Exemple 1

Dans cet exemple, une requête brute est lue à partir d’un socket via une fonction d’assistance, et la réponse est renvoyée via le même socket.

struct QUERY_RAW_CALLBACK_CONTEXT
{  
    DNS_QUERY_RAW_RESULT    *queryResults;
    HANDLE                  event;
};

VOID
CALLBACK
QueryRawCallback(
    _In_    VOID                  *queryContext,
    _In_    DNS_QUERY_RAW_RESULT  *queryResults
)
{
    QUERY_RAW_CALLBACK_CONTEXT *context = static_cast<QUERY_RAW_CALLBACK_CONTEXT *>(queryContext);

    //
    //  Capture the results of the query. Note that the DNS_QUERY_RAW_RESULT structure needs to
    //  be freed later with DnsQueryRawResultFree.
    //

    context->queryResults = queryResults;   

    SetEvent(context->event);
}

DWORD
HandleDnsQueryFromSocket(
    _In_ SOCKET socket
)
{
    DWORD errorStatus = ERROR_SUCCESS;
    DWORD waitStatus = 0;
    DNS_QUERY_RAW_REQUEST request = {0};
    DNS_QUERY_RAW_CANCEL cancel = {0};
    QUERY_RAW_CALLBACK_CONTEXT context = {0};
    CHAR opaqueSourceAddr[DNS_ADDR_MAX_SOCKADDR_LENGTH];
    ULONG opaqueSourceAddrSize = sizeof(opaqueSourceAddr);

    //
    //  ReceiveDnsQueryBytesFromSocket is a function that reads bytes from a socket
    //  that contains a wire-format DNS query, and gets information about the source
    //  address. It allocates the raw query buffer with HeapAlloc of size
    //  request.dnsQueryRawSize. Note that this function is just an example, and does
    //  not exist in the API.
    //
    errorStatus = ReceiveDnsQueryBytesFromSocket(socket,
                                                 &request.dnsQueryRaw,
                                                 &request.dnsQueryRawSize,
                                                 opaqueSourceAddr,
                                                 opaqueSourceAddrSize);
    if (errorStatus != ERROR_SUCCESS)
    {
        goto Exit;
    }

    context.event = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (context.event == NULL)
    {
        errorStatus = GetLastError();
        goto Exit;
    }

    //
    //  dnsQueryRaw is being used instead of dnsQueryName and dnsQueryType.
    //
    request.dnsQueryName = NULL;
    request.dnsQueryType = 0;

    request.version = DNS_QUERY_RAW_REQUEST_VERSION1; 
    request.resultsVersion = DNS_QUERY_RAW_RESULTS_VERSION1; 
    request.queryOptions = DNS_QUERY_BYPASS_CACHE;
    request.interfaceIndex = 0;
    request.queryCompletionCallback = &QueryRawCallback;
    request.queryContext = &context;
    request.queryRawOptions = 0;
    request.customServersSize = 0;
    request.customServers = NULL;
    request.protocol = DNS_PROTOCOL_UDP;
    memcpy_s(request.maxSa,
             sizeof(request.maxSa),
             opaqueSourceAddr,
             opaqueSourceAddrSize);

    errorStatus = DnsQueryRaw(&request, &cancel);
    if (errorStatus != DNS_REQUEST_PENDING)
    {
        goto Exit;
    }

    waitStatus = WaitForSingleObject(context.event, INFINITE);
    if (waitStatus != WAIT_OBJECT_0)
    {
        errorStatus = GetLastError();
        goto Exit;
    }

    //
    //  SendDnsResponseBytesToSocket is a function that writes a buffer containing a
    //  DNS response to a socket. Depending on the queryStatus, it can send other
    //  messages on the socket to indicate whether the socket should be closed, such as if
    //  the queryStatus indicates an internal DNS failure. Note that this function is
    //  just an example, and does not exist in the API.
    //
    errorStatus = SendDnsResponseBytesToSocket(socket,
                                               context.queryResults->queryStatus,
                                               context.queryResults->queryRawResponse,
                                               context.queryResults->queryRawResponseSize);

Exit:
    if (request.dnsQueryRaw != NULL)
    {
        HeapFree(GetProcessHeap(), 0, request.dnsQueryRaw);
        request.dnsQueryRaw = NULL;
    }

    if (context.queryResults != NULL)
    {
        DnsQueryRawResultFree(context.queryResults);
        context.queryResults = NULL;
    }

    if (context.event != NULL)
    {
        CloseHandle(context.event);
        context.event = NULL;
    }

    return errorStatus;
}

Exemple 2

Dans cet exemple, la requête est lancée avec un nom et un type de requête, mais est ensuite annulée avec DnsCancelQueryRaw.

struct QUERY_RAW_CALLBACK_CONTEXT
{
    DNS_QUERY_RAW_RESULT    *queryResults;
    HANDLE                  event;
};

VOID
CALLBACK
QueryRawCallback(
    _In_    VOID                  *queryContext,
    _In_    DNS_QUERY_RAW_RESULT  *queryResults
)
{
    QUERY_RAW_CALLBACK_CONTEXT *context = static_cast<QUERY_RAW_CALLBACK_CONTEXT *>(queryContext);

    //
    //  Capture the results of the query. Note that this structure needs to
    //  be freed later with DnsQueryRawResultFree.
    //

    context->queryResults = queryResults;

    SetEvent(context->event);
}

DWORD
CallDnsQueryRawAndCancel(
    _In_    PWSTR                       queryName,
    _In_    USHORT                      queryType,
    _In_    ULONG                       interfaceIndex,
    _In_    SOCKADDR_INET               *sourceAddr,
    _In_    ULONG                       protocol,
    _In_    DNS_CUSTOM_SERVER           *customServers,
    _In_    ULONG                       customServersSize,
    _Inout_ QUERY_RAW_CALLBACK_CONTEXT  *context
)
{
    DWORD errorStatus = ERROR_SUCCESS;
    DWORD waitStatus = 0;
    DNS_QUERY_RAW_REQUEST request = {0};
    DNS_QUERY_RAW_CANCEL cancel = {0};

    request.version = DNS_QUERY_RAW_REQUEST_VERSION1;
    request.resultsVersion = DNS_QUERY_RAW_RESULTS_VERSION1; 
    request.dnsQueryRawSize = 0;
    request.dnsQueryRaw = NULL;
    request.dnsQueryName = queryName;
    request.dnsQueryType = queryType;
    request.queryOptions = DNS_QUERY_BYPASS_CACHE;
    request.interfaceIndex = interfaceIndex;
    request.queryCompletionCallback = &QueryRawCallback;
    request.queryContext = context;
    request.queryRawOptions = 0;
    request.customServersSize = customServersSize;
    request.customServers = customServers;
    request.protocol = protocol;
    request.sourceAddr = *sourceAddr;

    errorStatus = DnsQueryRaw(&request, &cancel);
    if (errorStatus != DNS_REQUEST_PENDING)
    {
        goto Exit;
    }

    //
    //  Cancel the query with the provided cancel handle.
    //

    errorStatus = DnsCancelQueryRaw(&cancel);
    if (errorStatus != ERROR_SUCCESS)
    {
        goto Exit;
    }

    //
    //  Wait for the callback to indicate that the query has completed. Note that it
    //  is possible for the query to complete successfully or fail for another reason
    //  before the DnsCancelQueryRaw call is made, so the queryStatus member of
    //  DNS_QUERY_RAW_RESULT can be used to determine what happened.
    //

    waitStatus = WaitForSingleObject(context->event, INFINITE);
    if (waitStatus != WAIT_OBJECT_0)
    {
        errorStatus = GetLastError();
        goto Exit;
    }

    errorStatus = context.queryResults->queryStatus;

    if (errorStatus == ERROR_CANCELLED)
    {
        //
	    //  DNS query was successfully cancelled.
	    //
    }	
    else if (errorStatus != ERROR_SUCCESS)
    {
        //
	    //  DNS query failed before it was cancelled.
	    //
    }
    else
    {
        //
	    //  DNS query succeeded before it was cancelled, and can contain valid results.
        //  The other fields of context.queryResults to be processed as in Example 1.
	    //
    }

    //
    //  The context is owned by the caller of this function, and it will be cleaned up there.
    //

Exit:
    return errorStatus;
}

Configuration requise

Condition requise Valeur
Plateforme cible Windows
En-tête windns.h
Bibliothèque dnsapi.lib
DLL dnsapi.dll