You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GetAddrInfoExW调用异常:仅获取IPv4地址,无法返回IPv6地址

GetAddrInfoExW仅返回IPv4地址的问题排查与解决

问题概述

使用GetAddrInfoExW函数解析主机名(如google.com)时,指定hints.ai_family = AF_UNSPEC但仅返回IPv4地址;指定AF_INET6时查询失败,错误码11004。nslookup可正常获取IPv4和IPv6地址。

相关代码片段

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <thread>
#include <atomic>
#pragma comment(lib, "ws2_32.lib")
#define MAX_ADDRESS_STRING_LENGTH   64

struct DNS_QUERY_CONTEXT
{
    OVERLAPPED uOverlapped;
    PADDRINFOEX uResult;
    HANDLE uCancelOpsHandle;
};

bool InitWinsock()
{
    WSADATA wsaData;
    return WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
}

void CALLBACK LookupServiceCompletionRoutine(DWORD dwError, DWORD dwBytes, LPWSAOVERLAPPED lpOverlapped)
{
    if (dwError != 0) {
        std::cout << "Failed to resolve DNS " << dwError;
        return;
    }
    DNS_QUERY_CONTEXT * context = (DNS_QUERY_CONTEXT *) lpOverlapped;
    ADDRINFOEX * ptr = context->uResult;
    
    if (ptr == NULL) {
        std::cout << "No results found\n";
        return;
    }
    int i = 1;
    wchar_t ipstringbuffer [128];
    while (ptr != NULL) {
        std::cout << "GetAddrInfoEx response " << i++ << std::endl;
        std::cout << "	Flags: " << ptr->ai_flags << std::endl;
        std::cout << "	Family: ";
        switch (ptr->ai_family) {
            case AF_UNSPEC:
                std::cout << "UNSPEC (Unspecified)" << std::endl;
                break;
            case AF_INET:
            { 
                std::cout << "AF_INET (IPv4)" << std::endl;
                struct sockaddr_in * sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr; 
                InetNtop(AF_INET, &(sockaddr_ipv4->sin_addr), ipstringbuffer, INET_ADDRSTRLEN);
                std::wcout << L"	IPv4 Address: " << ipstringbuffer << std::endl;
                break;
            }
            case AF_INET6:
            { // IPv6
                std::cout << "AF_INET6 (IPv6)" << std::endl;
                struct sockaddr_in6 * sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
                InetNtop(AF_INET6, &(sockaddr_ipv6->sin6_addr), ipstringbuffer, INET6_ADDRSTRLEN);
                std::wcout << L"	IPv6 Address: " << ipstringbuffer << std::endl;
                break;
            }
            default:
                std::cout << "Unknown Family: " << ptr->ai_family << std::endl;
                break;
        }
        ptr = ptr->ai_next;
    }
    FreeAddrInfoEx(context->uResult);
    delete context; 
}

int main()
{
    DNS_QUERY_CONTEXT * context;
    ADDRINFOEXW hints;
    const wchar_t * query = L"google.com";
    int error;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;  // IPv4 or IPv6
    hints.ai_socktype = 0;
    hints.ai_protocol = 0;
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr =  NULL;
    hints.ai_next = NULL;
    context = new DNS_QUERY_CONTEXT;
    ZeroMemory(context, sizeof(DNS_QUERY_CONTEXT));
    if (!InitWinsock()) {
        std::cerr << "WSAStartup failed" << std::endl;
        return 1;
    }
    context->uOverlapped.hEvent = NULL;
    error = GetAddrInfoExW(
        query,          // Hostname to resolve
        NULL,           // Service name
        NS_DNS,         // Namespace
        NULL,           // Query context
        &hints,         // Hints
        &context->uResult,  // Result
        NULL,           // Timeout
        &context->uOverlapped, // Overlapped structure
        LookupServiceCompletionRoutine, // Completion routine
        &context->uCancelOpsHandle // Cancel handle
    );
    if (error != WSA_IO_PENDING) {
        std::cerr << "GetAddrInfoExW failed: " << WSAGetLastError() << std::endl;
        delete context;
        WSACleanup();
        return 1;
    }
    std::cout << "DNS query initiated, waiting for results..." << std::endl;
   
    while (true);
    WSACleanup();
    return 0;
}

原因分析

  1. hints结构参数缺失:默认情况下,设置AF_UNSPEC时,GetAddrInfoExW可能优先返回系统倾向的地址族(如IPv4),不会主动返回所有可用地址类型,需显式设置标志强制获取全量结果。
  2. 错误码11004含义:该错误为WSANO_DATA,表示请求名称有效但无对应数据记录。指定AF_INET6时触发此错误,多因缺少必要标志导致解析逻辑未正确请求IPv6记录。
  3. 系统解析策略影响:部分系统配置了IPv4优先的解析策略,即使DNS存在IPv6记录,GetAddrInfoExW也仅返回IPv4结果,除非显式要求。

解决方案

1. 修改hints结构的ai_flags参数

在初始化hints时添加AI_ALL | AI_V4MAPPED标志,强制返回所有地址族结果:

ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_flags = AI_ALL | AI_V4MAPPED; // 新增标志
hints.ai_addrlen = 0;
hints.ai_canonname = NULL;
hints.ai_addr =  NULL;
hints.ai_next = NULL;
  • AI_ALL:强制返回所有匹配的IPv4和IPv6地址
  • AI_V4MAPPED:当IPv6地址不可用时,返回IPv4映射的IPv6地址(可选,按需调整)

2. 优化GetAddrInfoExW调用参数

添加超时参数,避免因超时导致仅返回部分结果:

struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;

error = GetAddrInfoExW(
    query,
    NULL,
    NS_DNS,
    NULL,
    &hints,
    &context->uResult,
    &timeout, // 传入超时参数
    &context->uOverlapped,
    LookupServiceCompletionRoutine,
    &context->uCancelOpsHandle
);

3. 验证系统IPv6配置

  • 确认网络适配器已启用IPv6
  • 通过nslookup -type=AAAA google.com验证DNS服务器可返回IPv6记录

4. 调整系统解析优先级(可选)

Windows系统中可通过以下命令提升IPv6解析优先级:

netsh interface ipv6 set prefixpolicy ::/0 50 0

内容的提问来源于stack exchange,提问作者Harshal Goyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:40:01