IPv6 域名解析原理及编程实现

2009-09-24 09:36:51 旧日重来

随着 IPv4 资源逐渐耗尽,IPv6 (Internet Protocol version 6) 网络的部署已开始进行,相信已经有不少朋友已经开始使用 v6 的网络了。和 IPv4 最显著的不同是每个 v6 的 IP 地址包含 128 位(16 个字节),相比 v4 来说极大的扩展了地址空间。但是,这也使得 v6 的网络在使用时特别是编程的时候和 v4 的情况不大兼容。本文介绍了针对 IPv6 的 DNS 域名解析知识和编程实现。

由于 DNS 协议的特点,原有的 DNS 系统几乎不需要做什么改变就已经直接支持 IPv6 的域名解析了。有意思的是,客户机并不用接入 v6 的网络甚至根本不需要安装 v6 组件(例如默认的 Windows XP 系统)就可以请求解析 v6 的地址,只需要系统可以与一个有效的 DNS 服务器建立连接(例如通过 DHCP 自动获取的 DNS 服务器),而无论这个 DNS 服务器是 v6 还是 v4 的。事实上,解析 v6 地址与 v4 唯一的不同就是 v4 查询域名的 A 记录而 v6 查询域名的 AAAA 记录。

下面的例子演示了如何通过 Windows 的 nslookup 命令和 BIND 中的 dig 命令查询 gipv6.aulddays.com 这个 IPv6 域名的方法(注意,使用的 OpenDNS 服务器 208.67.222.222 就是通过 IPv4 连接的):

>nslookup -querytype=AAAA gipv6.aulddays.com
Server:  resolver
Address:1.opendns.com  208.67.222.222

Non-authoritative answer:
Name:    gipv6.aulddays.com
Address:  2001:4860:b004::68
>dig AAAA gipv6.aulddays.com

; <<>> DiG 9.4.2 <<>> AAAA gipv6.aulddays.com
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 943
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;gipv6.aulddays.com. IN AAAA

;; ANSWER SECTION:
gipv6.aulddays.com. 1800 IN AAAA 2001:4860:b004::68

;; Query time: 360 msec
;; SERVER: 208.67.222.222#53(208.67.222.222)
;; WHEN: Sat Sep 19 16:13:18 2009
;; MSG SIZE rcvd: 64

下面说说如何在程序中解析 IPv6 的域名。传统的 v4 地址是使用 gethostbyname() 函数解析,虽然可以通过修改编译选项的方式强制它工作在 v6 状态,但这样也失去了兼容性。为此,最好使用更新的 getaddrinfo() 函数,该函数同时支持 v4 和 v6 域名的解析,VC++ 中的示例代码如下:

#include "stdio.h"
#include "Ws2tcpip.h"

#pragma comment(lib, "Ws2_32.lib")  // getaddrinfo 需要的 lib

int main(int argc, char * argv[])
{
    const char *strDomain2Resolve = "gipv6.aulddays.com";

    // 初始化 Winsock
    WSADATA wsaData;
    int nStatus = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (NO_ERROR != nStatus)
    {
        printf("WSAStartup() 错误\n");
        return -1;
    }

    addrinfo Hints, *AddrList;
    memset(&Hints, 0, sizeof(Hints));
    Hints.ai_family = PF_INET6; // IPv6 address family

    // 进行域名解析
    nStatus = getaddrinfo(strDomain2Resolve, NULL, &Hints, &AddrList);
    if (NO_ERROR != nStatus)
    {
        // 处理出错的情况,
        // 例如目标域名没有对应的 AAAA 记录
        printf("getaddrinfo() 失败,错误信息为 %d: %s\n",
            nStatus, gai_strerror(nStatus));
        return -1;
    }

    // 打印所有找到的地址(一个域名可能对应多个 IP 地址)
    printf("已解析出下列地址:\n");
    char pBuf[64];  // 打印缓冲
    for(addrinfo *i = AddrList; i; i = i->ai_next)
    {
        // 取得一个解析出的地址
        in6_addr DnsAddr = ((sockaddr_in6 *)i->ai_addr)->sin6_addr;
        // 得到可打印版本
        inet_ntop(AF_INET6, &DnsAddr, pBuf, 64);
        printf("%s\n", pBuf);
    }

    // 一般来说,客户端程序应轮询或使用解析出的 IP 列表中的第一个即可
    // (如果解析出多个地址的话)
    in6_addr AddrToUse = ((sockaddr_in6 *)AddrList->ai_addr)->sin6_addr;

    freeaddrinfo(AddrList);

    WSACleanup();
}

查看:原文地址;来源:live.aulddays.com


注意:本站所有文章除特别说明外均为原创,版权所有,转载请务必以超链接方式注明作者出处,并禁止用作商业用途