引言
你在浏览器中输入 www.baidu.com,敲下回车,网页就打开了。整个过程不到一秒。但在这背后,有一个至关重要的步骤:把人类能记住的域名,翻译成机器能识别的 IP 地址。
这个翻译工作,就是 DNS(Domain Name System,域名系统)完成的。
没有 DNS,你就得记住 110.242.68.66 这样的数字才能上网。DNS 是互联网的"电话簿"------它让互联网对人类友好。

第一部分:域名的基础知识
一、域名层级结构
域名是从右往左读的层级结构:

| 层级 | 示例 | 说明 |
|---|---|---|
| 根域 | . |
最高层,13 组根服务器 |
| 顶级域(TLD) | .com、.org、.cn |
通用顶级域 / 国家顶级域 |
| 二级域 | example |
组织/公司注册的域名 |
| 子域 | www、api、mail |
自行分配 |
二、顶级域的分类

第二部分:DNS 查询过程
一、DNS 服务器分类

二、递归查询与迭代查询

三、完整解析过程

第三部分:DNS 记录类型
一、常见记录类型
| 记录类型 | 全称 | 作用 | 示例 |
|---|---|---|---|
| A | Address | 域名 → IPv4 地址 | www.example.com → 93.184.216.34 |
| AAAA | IPv6 Address | 域名 → IPv6 地址 | www.example.com → 2606:2800:... |
| CNAME | Canonical Name | 别名 → 另一个域名 | blog.example.com → www.example.com |
| MX | Mail Exchange | 邮件服务器地址 | example.com → mail.example.com |
| NS | Name Server | 该域名的权威 DNS 服务器 | example.com → ns1.example.com |
| TXT | Text | 文本记录(验证、SPF) | "v=spf1 include:..." |
| SOA | Start of Authority | 域名的起始授权记录 | 管理信息 |
| PTR | Pointer | IP → 域名(反向解析) | 34.216.184.93 → www.example.com |
二、A 记录与 CNAME 记录

三、MX 记录

第四部分:DNS 缓存与 TTL
一、TTL 是什么
TTL(Time To Live)是 DNS 记录的缓存时间,单位秒。
cpp
www.example.com. 3600 IN A 93.184.216.34
↑
TTL = 3600 秒(1小时)
二、各级缓存

三、TTL 的权衡
| TTL 值 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 长(如 86400) | 减少 DNS 查询,加快访问 | 修改 IP 后生效慢 | 稳定的服务 |
| 短(如 60) | 修改 IP 后快速生效 | 查询频繁,增加负载 | 频繁变更的服务 |
第五部分:常用 DNS 工具
一、nslookup
bash
# 基本查询
nslookup www.baidu.com
# 输出:
# Server: 192.168.1.1
# Address: 192.168.1.1#53
#
# Non-authoritative answer:
# Name: www.baidu.com
# Address: 110.242.68.66
# 指定 DNS 服务器查询
nslookup www.baidu.com 8.8.8.8
# 查询 MX 记录
nslookup -type=mx example.com
# 查询 NS 记录
nslookup -type=ns example.com
二、dig(Linux 推荐)
bash
# 基本查询
dig www.baidu.com
# 输出:
# ;; ANSWER SECTION:
# www.baidu.com. 300 IN CNAME www.a.shifen.com.
# www.a.shifen.com. 300 IN A 110.242.68.66
# 只显示答案
dig +short www.baidu.com
# 查询指定类型
dig MX example.com
dig NS example.com
dig TXT example.com
# 指定 DNS 服务器
dig @8.8.8.8 www.baidu.com
# 跟踪完整解析过程
dig +trace www.baidu.com
三、host
bash
host www.baidu.com
host -t MX example.com
四、DNS 服务器推荐
| 提供商 | IPv4 | 特点 |
|---|---|---|
| 8.8.8.8 / 8.8.4.4 | 全球通用,稳定 | |
| Cloudflare | 1.1.1.1 / 1.0.0.1 | 速度快,注重隐私 |
| 阿里 | 223.5.5.5 / 223.6.6.6 | 国内快 |
| 腾讯 | 119.29.29.29 | 国内快 |
第六部分:DNS 安全问题
一、DNS 劫持

二、DNS 欺骗(DNS Spoofing)
攻击者在 DNS 响应到达前,抢先发一个伪造的响应给客户端。防御方式:
-
DNSSEC:对 DNS 响应进行数字签名
-
DoH / DoT:加密 DNS 查询
三、DoH 和 DoT

第七部分:C 语言实现 DNS 查询
一、使用 getaddrinfo(推荐)
cpp
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int main() {
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // IPv4 或 IPv6
hints.ai_socktype = SOCK_STREAM;
// DNS 解析
if ((status = getaddrinfo("www.baidu.com", NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return 1;
}
printf("www.baidu.com 的 IP 地址:\n");
// 遍历结果
for (p = res; p != NULL; p = p->ai_next) {
void* addr;
char* ipver;
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
// 转成字符串
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
freeaddrinfo(res);
return 0;
}
二、使用 gethostbyname(旧版,不推荐)
cpp
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
int main() {
struct hostent* host = gethostbyname("www.baidu.com");
if (host == NULL) {
printf("解析失败\n");
return 1;
}
printf("域名:%s\n", host->h_name);
for (int i = 0; host->h_addr_list[i] != NULL; i++) {
printf(" IP: %s\n", inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
}
return 0;
}
第八部分:面试题
1. Q:DNS 解析过程?
A:① 检查浏览器缓存 → ② 检查系统缓存(hosts)→ ③ 本地 DNS 缓存 → ④ 本地 DNS 向根服务器迭代查询 → ⑤ 根返回 TLD 地址 → ⑥ TLD 返回权威服务器地址 → ⑦ 权威服务器返回 IP。
2. Q:递归查询和迭代查询的区别?
A:递归查询是客户端发给本地 DNS,本地 DNS 负责查到底再返回结果。迭代查询是本地 DNS 发给各级 DNS,每级只告诉它下一步该问谁。
3. Q:A 记录和 CNAME 记录的区别?
A:A 记录直接指向 IP 地址,CNAME 记录指向另一个域名(别名)。CNAME 通常用于 CDN、多域名指向同一服务。
4. Q:DNS 为什么用 UDP?
A:DNS 查询数据量小(通常一个包就能装下),UDP 无需建立连接,速度快。当响应超过 512 字节时会切换到 TCP(或使用 EDNS0 扩展)。
5. Q:什么是 DNS 劫持?怎么防?
A:DNS 劫持是攻击者篡改 DNS 响应,把域名指向错误的 IP。防御方式:使用可信 DNS、HTTPS(证书验证)、DNSSEC、DoH/DoT。
总结
一、核心要点
| 要点 | 内容 |
|---|---|
| DNS 作用 | 域名 → IP 地址 |
| 域名结构 | 根 → TLD → 二级域 → 子域 |
| 查询方式 | 客户端→本地 DNS 用递归,本地 DNS→各级用迭代 |
| 记录类型 | A、AAAA、CNAME、MX、NS、TXT |
| 缓存 | 浏览器 → 系统 → hosts → 本地 DNS |
| TTL | 缓存时间,长 TTL 快但更新慢,短 TTL 灵活但查询多 |
| 安全 | DNS 劫持、DNS 欺骗、DoH/DoT 加密 |
二、一句话记忆
DNS 把域名翻译成 IP。客户端向本地 DNS 发递归查询,本地 DNS 向根、TLD、权威服务器迭代查询。常见记录有 A(IP)、CNAME(别名)、MX(邮件)。用 nslookup/dig 排查,用 DoH/DoT 防窃听。