为什么DNS使用UDP而不是TCP?

DNS在进行区域传输的时候使用TCP,普通的查询使用UDP。为什么查询是使用UDP呢?网络上大部分答案都说UDP性能更好,打开网页速度快。如果是这样的…
关注者
154
被浏览
180,554

25 个回答

衡量计算机通信快慢的指标是“响应时间”,即从用户发出通信指令(输入网址敲回车键)开始,到用户看到完整页面为止,所流逝的时间。


响应时间(Response Time)

以浏览器为例,这个响应时间大体分为三部分:

响应时间= DNS域名解析时间 + TCP 连接建立时间 + HTTP交易时间

如果让响应时间尽可能小,只有让等号右侧的三者尽可能小。

TCP连接是固定的三次握手,所以很难有进一步缩小的空间。

HTTP交易,基于Request / Response,也很难有提升的空间。

所以,只能让DNS域名解析的时间越小越好。


域名解析

采用TCP传输,则域名解析时间为:

DNS域名解析时间 = TCP连接时间 + DNS交易时间


采用UDP传输,则域名解析时间为:

DNS域名解析时间 = DNS交易时间

很显然,采用UDP传输,DNS域名解析时间更小。


读者可能会说,不就多一次TCP连接时间吗?

NO!

在很多时候,用户在访问一些冷门网站时,由于DNS服务器没有冷门网站的解析缓存,需要到域名根服务器、一级域名服务器、二级域名服务器迭代查询,直到查询到冷门网站的权威服务器,这中间可能涉及到多次的查询。

如果使用TCP传输,多几次查询,就多几次TCP连接时间,这多出来的时间不容小觑。


UDP传输的弱点

由于历史的原因,互联网上物理链路的最小MTU = 576,基于UDP传输的DNS为了限制报文不超过576,所以将DNS报文限制在512字节。

这样一旦DNS查询应答超过512字节,基于UDP的DNS就只有截短为512字节,那么用户得到的DNS应答就是不完整的。

为了克服这种困难,最简单的方式就是使用TCP,来重新查询。尽管交易时间可能比较长,但毕竟可以得到完整的答案,总比得到不完整的答案要好。


难道UDP没有办法传输超过大于576字节的数据吗?

并不是这样。

DNS是由于自身的限制,原因上述文字已经解释。

当基于UDP传输的DNS有1000字节需要传输时,会将1000字节砍成两个500字节的报文传输?

不会! 只会保留前面的512字节,剩下的488字节会抛弃!


为什么要这样?

因为DNS没有字段来标识报文ID,比如1、2、3,所以默认只有一个报文,剩下的多余数据只有被扔的份!


互联网的不安全性

互联网经过多年的发展,鱼龙混杂,欺骗横行,用户的域名服务器是8.8.8.8,用户能够拍着胸脯说,从8.8.8.8返回的DNS应答真的就是8.8.8.8回答的吗?

不能!

无论是采用UDP、还是TCP传输,都无法保证!

怎么办呢?

如果8.8.8.8 返回的应答,使用自己的私钥签名,那么主机得到应答之后,先检查签名是否来自于8.8.8.8的签名,如果是,接收。 如果不是,拒绝!

这样是不是就可以拍着胸脯说,应答真的是来自于8.8.8.8。

但签名带来了很多负面问题,DNS应答由于携带了证书链,整个报文有几千字节,无法使用UDP传输,那也只好使用TCP传输了。

总结一下mp.weixin.qq.com/s/BF0E

前言

前面发布了一篇关于PowerDNS-Admin搭建教程,这篇教程全程都是在Ubuntu系统中原始部署,有些人反馈太麻烦了,故我把之前使用docker部署的最佳实践给分享出来,希望能帮助使用PowerDNS权威服务器的朋友们。

部署

前提需要部署好PowerDNS权威服务器,然后利用PowerDNS-Admin管理权威服务器的记录。数据存储在MySQL数据库中。

这里需要两个数据库实例,一个是权威服务器的RR记录数据,这里以「dns_auth」为实例名,一个是PowerDNS-Admin本身的数据信息,这里以「dns_pda」为实例名。使用docker compose部署安装为例:

# docker 安装 自行查看官网 这里以Ubuntu 22.04 LTS为例
# 拉取PowerDNS-Admin的镜像仓库
sudo docker pull powerdnsadmin/pda-legacy

# 新建docker-compose.yml文件
sudo vim docker-compose.yml

version: "3"

services:
  app:
    image: powerdnsadmin/pda-legacy:latest
    container_name: powerdns_admin
    ports:
      - "80:80"
    logging:
      driver: json-file
      options:
        max-size: 50m
    environment:
      - SQLALCHEMY_DATABASE_URI=mysql://test:123456qwe@172.17.40.36/dns_pda
      - GUNICORN_TIMEOUT=60
      - GUNICORN_WORKERS=2
      - GUNICORN_LOGLEVEL=DEBUG
      
# 运行
sudo docker compose up -d

参数说明: SQLALCHEMY_DATABASE_URI是PowerDNS-Admin的数据库实例信息,这里建议使用MySQL,并且端口一定是默认端口3306,因为参数没有提供端口修改,无法修改端口,除非修改源码去重新构建docker镜像并且部署。

test:123456qwe是数据库用户名和密码,172.17.40.36是数据库实例IP,dns_pda是数据库的实例名,上面的环境变量信息自行修改自己的配置信息。

注意事项

「dns_auth」为PowerDNS权威服务器的数据库实例名,需要在PowerDNS的权威服务器中配置gmysql信息。

docker compose运行的时候,会默认不使用docker0网桥,新建一个网桥,如果出现网段冲突,可以直接修改配置文件,指定新建网桥的网段信息,如下所示:

# 新建docker配置文件
sudo vim /etc/docker/daemon.json

{
  "bip": "172.19.131.1/24",
  "default-address-pools": [ {"base": "172.19.132.0/24", "size": 25 } ],
  "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}

# 参数说明
bip 是指定docker0网桥的网段信息
default-address-pools 是指定新建网桥的默认配置网段信息 自行规划好网段和子网大小
registry-mirrors docker镜像仓库自行更换

部署后配置

打开Web界面,到登录界面,PowerDNS没有管理员用户,登录之前需要首先注册第一个用户,就是管理员用户。

打开Setting,点击Server,配置API信息:

到此就完成基本配置,完善了之前PowerDNS-Admin的搭建,也简化了之前的搭建步骤,从DNS的递归到权威以及第三方Web界面管理权威服务器实现DNS记录CUDR。