DnsQueryRaw 함수(windns.h)
중요
일부 정보는 상용 출시 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적이거나 묵시적인 보증도 하지 않습니다.
DNS 쿼리를 포함하는 원시 패킷 또는 쿼리 이름 및 형식을 허용하는 DNS 쿼리를 수행할 수 있습니다. 호스트 시스템의 설정 및 구성으로 쿼리를 보강할 수 있습니다.
- 이미 형식이 지정된 원시 DNS 쿼리 패킷에 새 쿼리 옵션 및 사용자 지정 서버를 적용할 수 있습니다.
- 또는 대신 쿼리 이름 및 형식을 제공하고 구문 분석된 레코드와 원시 결과 패킷을 모두 수신할 수 있습니다(클라이언트가 서버에서 받은 모든 정보와 상호 작용할 수 있음).
쿼리는 비동기적으로 수행됩니다. 및 결과는 구현하는 DNS_QUERY_RAW_COMPLETION_ROUTINE 비동기 콜백 함수에 전달됩니다. 쿼리를 취소하려면 DnsCancelQueryRaw를 호출합니다.
구문
DNS_STATUS DnsQueryRaw(
DNS_QUERY_RAW_REQUEST *queryRequest,
DNS_QUERY_RAW_CANCEL *cancelHandle
);
매개 변수
queryRequest
형식: _In_ DNS_QUERY_RAW_REQUEST*
쿼리 요청입니다.
cancelHandle
형식: _Inout_ DNS_QUERY_RAW_CANCEL*
쿼리를 취소해야 하는 경우 DnsCancelQueryRaw 에 전달할 수 있는 취소 핸들을 가져오는 데 사용됩니다.
반환 값
성공 또는 실패를 나타내는 DNS_STATUS 값입니다. DNS_REQUEST_PENDING 반환되면 쿼리가 완료되면 시스템은 queryRequest의 queryCompletionCallback 멤버에 전달한 DNS_QUERY_RAW_COMPLETION_ROUTINE 구현을 호출합니다. 해당 콜백은 성공한 경우 쿼리의 결과 또는 실패 또는 취소를 수신합니다.
설명
원시 패킷의 구조는 RFC 1035에 설명된 대로 DNS 쿼리 및 응답의 유선 표현입니다. 12 바이트 DNS 헤더 뒤에 쿼리에 대한 질문 섹션 또는 응답에 대한 레코드의 가변 번호(0일 수 있음)가 뒤따릅니다. TCP를 사용하는 경우 원시 패킷에 2 바이트 길이 필드 접두사를 지정해야 합니다. 이 API를 사용하여 호스트 NRPT 규칙을 적용하거나 암호화된 DNS 쿼리를 수행할 수 있습니다.
예제
예 1
이 예제에서는 도우미 함수를 통해 소켓에서 원시 쿼리를 읽고 응답은 동일한 소켓을 통해 다시 전송됩니다.
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;
}
예 2
이 예제에서 쿼리는 쿼리 이름 및 형식으로 시작되지만 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;
}
요구 사항
요구 사항 | 값 |
---|---|
대상 플랫폼 | Windows |
헤더 | windns.h |
라이브러리 | dnsapi.lib |
DLL | dnsapi.dll |