Querying DNS Records Using WINAPI in C++

Querying DNS Records Using WINAPI in C++

KaguraiYoRoy
20-03-2025 / 0 Comments / 118 Views / Checking if indexed by search engines...

This article has been migrated from an old blog (a kind of cyber reincarnation). Corrections are welcome if any errors are found.

Background

Multiple access endpoints were configured for an API to handle service unavailability in certain regions where access might be blocked. Initially, I considered creating a file within the website to store node information, but this approach proved unfeasible because regions with connectivity issues couldn't retrieve information about other endpoints. Then, the idea emerged to use DNS resolution records - specifically, a TXT record - to store the relevant node data for querying.

Implementation

Research

After searching on Bing, I found that most existing articles use sockets to directly send query packets. However, these methods typically only retrieve A and CNAME records, which wasn't suitable for my needs. Finally, I focused on the DnsQuery function mentioned in MSDN and found a sample article: Use DnsQuery to Resolve Host Names.

Function Analysis

According to the official documentation, the function requires the header windns.h and needs to link against the libraries Ws2_32.lib and Dnsapi.lib. The function parameters are as follows:

DNS_STATUS DnsQuery_A(
  [in]                PCSTR       pszName,
  [in]                WORD        wType,
  [in]                DWORD       Options,
  [in, out, optional] PVOID       pExtra,
  [out, optional]     PDNS_RECORD *ppQueryResults,
  [out, optional]     PVOID       *pReserved
);

Parameter Explanation:

  • pszName is the hostname to query.
  • wType is the query type, such as A record, CNAME, TXT, etc. Specific constants are documented by MSDN: DNS Constants.
  • Options literally means the query method. I used DNS_QUERY_STANDARD directly. Details can also be found in the documentation: DNS Constants.
  • pExtra and pReserved can simply be set to NULL.
  • ppQueryResultsis a pointer to the query results, of type PDNS_RECORD*. This requires passing a reference to the variable's value.
  • Return value: The DNS_STATUS type. If the query fails, it returns the corresponding error code from Winerror.h.

Usage

Understanding the usage method made it straightforward:
My TXT record domain is test.iyoroy.cn. The query code is as follows:

PDNS_RECORD pDnsRecord;
DNS_STATUS QueryRet = DnsQuery(L"test.iyoroy.cn", DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL);
if (QueryRet) {
    MessageBox(GhWnd, L"DNS query failed!\r\nWill use the default node.", L"Warning", MB_ICONERROR | MB_OK); 
}
std::wstring strQueryRes = *pDnsRecord->Data.TXT.pStringArray; // This is the query result.

Successfully implemented the functionality.

Postscript

TXT records automatically filter out spaces and line breaks. Therefore, I chose to store Base64 encoded data in the record, decode it when used, and then split it using stringstream. For Base64 decoding, I adapted the code from this article: Base64 Encoding and Decoding in C++. Below is the rewritten decoding function using wide characters:

After that, selecting an available node becomes possible.


Reference Articles:

2

Comments (0)

Cancel