UDP 协议是什么?UDP 全称 User Datagram Protocol,中文叫用户数据报协议,1980 年由 RFC 768 定义,工作在 TCP/IP 的传输层(对应 OSI 第 4 层),与 TCP 并列。它在 IP 之上只加了两样东西:端口号,用来区分同一台主机上的不同程序;校验和,用来发现数据在途中出错。除此之外它什么都不做:不握手、不确认、不重传、不排序、不控制发送速度,应用交给它多少字节,它就原样封装成一个数据报发出去。所以 UDP 首部只有 8 字节,发送时没有任何等待,适合 DNS 查询、时间同步、音视频、游戏这类“快比全重要”或者“一问一答”的场景。
UDP 工作在哪一层
UDP 位于传输层,下面是 IP,上面是应用程序。IP 包头的“协议”字段等于 17,表示里面装的是 UDP(TCP 是 6);系统收到后再按 UDP 首部里的目的端口,把数据交给监听该端口的程序。防火墙规则里的 -p udp、交换机 ACL 里的 udp 关键字,匹配的就是 IP 协议号 17。
UDP 之上还可以再叠一层“传输协议”,这是它在机房里越来越常见的原因:
QUIC 跑在 UDP 上,自己实现了可靠传输和加密,HTTP/3 就建立在 QUIC 之上;
VXLAN 把整个以太网帧装进 UDP(目的端口 4789),让二层网络跨三层网络延伸;
WireGuard、OpenVPN、IPsec 的 NAT 穿越也常用 UDP 承载隧道,里面的 TCP 连接自己负责重传。
“无连接、不可靠”具体指什么
对比项
UDP
TCP
建立连接
不需要,第一个包就携带数据
三次握手完成后才能发数据
确认与重传
没有,丢了就丢了
每段数据都要确认,超时重传
顺序
不保证,先发的可能后到
按序号重排后交给应用
流量与拥塞控制
没有,应用发多快就发多快
按接收窗口和网络拥塞情况调节速率
数据边界
保留:发一次就是一个数据报,收一次拿到完整的一个
字节流,没有消息边界,应用要自己分包
首部长度
固定 8 字节
20–60 字节
一对多
支持广播、组播
只能一对一
服务器状态
不需要为每个客户端维护连接
每个连接占一份状态和收发缓冲区
几个常见的误解:
“不可靠”不等于“经常丢包”。UDP 不会主动丢数据,丢包只发生在网络拥塞、链路出错或接收缓冲区满的时候,这些情况 TCP 一样会遇到;区别是 TCP 会补发,UDP 把怎么处理留给应用:DNS 超时重问,视频跳过这一帧,QUIC 自己重传。
校验和只能发现错误,不能纠正。校验失败的数据报被直接丢弃,应用既收不到它,也不会收到通知。
接收端来不及读也会丢。高速收包的 UDP 服务(如日志汇聚、流量采集)要关注 netstat -su 输出里的 receive buffer errors,持续增长说明程序读得不够快,需要调大 net.core.rmem_max 和程序自身的接收缓冲区。
UDP 报文格式:8 字节首部
0 15 16 31 (位)
+----------------------+----------------------+
| 源端口 Source Port | 目的端口 Dest Port |
+----------------------+----------------------+
| 长度 Length | 校验和 Checksum |
+----------------------+----------------------+
| 数据 Data(可变长) |
+---------------------------------------------+
字段
长度
含义
源端口
16 位
发送方的端口,对方回复时发回这个端口;不需要回复时可以填 0
目的端口
16 位
接收方程序监听的端口,如 DNS 的 53
长度
16 位
UDP 首部加数据的总字节数,最小 8(没有数据),最大 65535
校验和
16 位
覆盖伪首部(源 IP、目的 IP、协议号、UDP 长度)、UDP 首部和数据;IPv4 下可以填 0 表示不校验,IPv6 下原则上必须计算
伪首部把 IP 地址也纳入校验,用来发现“数据没错但送错了主机”的情况。也因为校验和包含 IP 地址,NAT 设备改写地址时必须同时更新 UDP 校验和。
用一个算例看各层的字节数:不带 EDNS 扩展、查询 www.example.com 的 A 记录(dig +noedns +noadflag www.example.com 发出的就是这样一个包):
部分
字节
说明
DNS 首部
12
事务 ID、标志位和各段计数
查询名
17
编码为 3www7example3com0:每段前加 1 字节长度,末尾 1 字节 0
查询类型与类别
4
类型 A 和类别 IN 各 2 字节
DNS 报文合计
33
即 UDP 的数据部分
UDP 首部
8
长度字段的值为 8 + 33 = 41
IPv4 首部
20
IP 总长度为 61
以太网头和 FCS
18
线路上的帧共 79 字节
用 tcpdump 能看到同样的数字:
tcpdump -i eth0 -nn udp port 53
# 10:20:31.508812 IP 198.51.100.23.51365 > 223.5.5.5.53: 4660+ A? www.example.com. (33)
括号里的 33 就是 UDP 数据部分(DNS 报文)的长度,4660 是 DNS 事务 ID,后面的 + 表示请求递归。加 -X 参数能看到十六进制原文:20 字节 IP 首部之后紧跟的 8 字节就是 UDP 首部,依次是源端口 c8a5(51365)、目的端口 0035(53)、长度 0029(41)和校验和。
UDP 用于哪些场景:常见服务与端口
服务
UDP 端口
为什么用 UDP
DNS
53
一问一答各一个包,先握手会让每次查询多一个往返
DHCP
服务端 67,客户端 68
客户端还没有 IP 地址,只能靠广播,TCP 做不到
TFTP
69
PXE 网卡固件里只能放下很简单的协议,TFTP 在 UDP 上自己逐块确认
NTP
123
时间戳讲究准时,重传过来的旧包反而有害
SNMP
161 查询,162 Trap
监控系统要轮询成百上千台设备,无连接开销小
Syslog
514
设备日志单向发送,偶尔丢一两条可以接受
IPMI(RMCP+)
623
BMC 资源有限,协议自带会话管理和重试
IKE / IPsec NAT 穿越
500 / 4500
VPN 隧道协商与承载
VXLAN
4789
封装二层帧,可靠性交给内层 TCP
WireGuard
常用 51820,可自定义
隧道协议,内层连接自己负责重传
HTTP/3(QUIC)
443
在 UDP 上自建可靠传输,避开 TCP 的队头阻塞
语音视频通话、直播、在线游戏
由应用协商或自定义
迟到的数据已经没用,宁可丢弃也不等待
不适合 UDP 的场景也很明确:文件传输、数据库、网页这类一个字节都不能错、又不打算自己实现重传的业务,直接用 TCP。另外,有些企业网和代理环境会整体限制 UDP,基于 UDP 的协议要准备好退回 TCP 的方案,HTTP/3 退回 HTTP/2 就是这样设计的。
服务器防火墙放行 UDP 和 TCP 有什么不同
1. 协议要单独写。 TCP 53 和 UDP 53 是两个端口,对外提供 DNS 两个都要放行;安全组里选“全部 TCP”,不包含任何 UDP 端口。
# iptables:对外提供 DNS,只允许内网访问 NTP
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp -s 10.0.0.0/8 --dport 123 -j ACCEPT
# firewalld:放行 WireGuard 的 UDP 端口
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload
# Windows 防火墙:协议参数写 UDP
New-NetFirewallRule -DisplayName "Syslog UDP 514" -Direction Inbound -Protocol UDP -LocalPort 514 -Action Allow
2. 状态防火墙靠超时判断“会话”。 UDP 没有 SYN 和 FIN,Linux 的连接跟踪按源地址、源端口、目的地址、目的端口和协议记录 UDP 流:看到第一个包记为 NEW,对方回包后记为 ESTABLISHED,一段时间没有包就删除记录。超时时间可以这样查看:
sysctl net.netfilter.nf_conntrack_udp_timeout net.netfilter.nf_conntrack_udp_timeout_stream
前者用于只有单向或零星往返的流,默认 30 秒;后者用于持续双向通信的流,时间更长,具体以内核版本为准。长时间不发包的 UDP 应用(部分 VPN、游戏、物联网设备)超过时限后会被当成新会话,入站方向又没放行时,服务器下发的数据就到不了,所以这类应用都会定时发送保活包。云平台的安全组和 NAT 网关也有各自的 UDP 超时,以平台文档为准。
3. 无状态 ACL 没法用 established 放行 UDP 回包。 交换机、路由器上的 ACL 一般不跟踪连接状态。思科 ACL 的 established 关键字依据的是 TCP 头里的 ACK、RST 标志位,对 UDP 不起作用。服务器向外查询 DNS 时,回包只能按“源端口为 53、目的端口在本机临时端口范围内”来放行(查询用的源端口是随机选的);而 UDP 的源端口可以随意伪造,这类规则的约束力比 TCP 弱得多。所以机房里 UDP 回程的控制,更多依赖服务器或边界上的状态防火墙。
4. 测试方法不同。 UDP 没有握手,端口扫描只能告诉你“没收到拒绝”。可靠的做法是一端发、一端看:
# 服务器上:抓目标端口的包,看请求有没有到达
tcpdump -nni any udp port 123
# 没有现成服务时,临时监听一个空闲端口(部分 nc 版本要写成 nc -u -l -p 9999)
nc -u -l 9999
# 客户端:发一行文字过去,服务器窗口里出现这行字就说明 UDP 能到达
echo hello | nc -u -w 1 203.0.113.10 9999
tcpdump 看得到请求、却没有应答,问题在服务本身;连请求都看不到,问题在路上的防火墙、安全组或 ACL。
5. 暴露在公网的 UDP 服务要防反射放大。 攻击者伪造受害者的源地址,向开放的 UDP 服务发小请求,服务把大得多的应答发给受害者。开放递归的 DNS、NTP、SNMP、Memcached(UDP 11211)、SSDP(UDP 1900)都曾被这样大规模利用。不需要对公网提供的 UDP 服务,只监听内网地址,或者在防火墙上限定来源;必须开放的,要限速并关闭能返回大量数据的功能。
UDP 大包与分片:MTU 要算进去
TCP 会按 MSS 把数据切成合适的段再发,UDP 不会:应用一次交给它 4000 字节,它就生成一个 4008 字节的数据报,超过链路 MTU 的部分由 IP 层分片。分片带来三个实际问题:
任何一片丢失,整个数据报作废。UDP 没有重传,丢包率被放大。
只有第一片带 UDP 首部。后续分片里没有端口号,按端口写的防火墙和 ACL 可能把它们丢掉,有的网络干脆丢弃所有分片。
IPv6 的中间路由器不做分片。超过路径 MTU 的包被丢弃,并回送 ICMPv6 “包过大”消息;这条消息再被过滤,就成了黑洞。
所以基于 UDP 的协议都会主动控制包长:DNS 社区在 2020 年的 DNS Flag Day 建议把 EDNS 缓冲区设为 1232 字节,应答更大时让客户端改用 TCP;QUIC 要求路径至少能通过 1200 字节的 UDP 载荷,在此基础上再探测更大的包长。机房里用到 UDP 封装时要把开销算进 MTU:VXLAN 每个包多出 50 字节(外层以太网头 14、IP 头 20、UDP 头 8、VXLAN 头 8),承载网的 MTU 至少设为 1550,虚拟机里才能继续使用 1500。
在机房里怎么落地
UDP 反射攻击能成立,前提是攻击者能发出伪造源地址的包。机房能做的,是在接入层就不让伪造来源的流量离开:Toplink DCIM 的 IP 地址管理 统一登记每个地址归属哪台服务器,交换机侧开启源地址校验后,只放行源 IP 属于该端口的流量,伪造来源的数据包直接丢弃;再配合 ARP 绑定把 IP 与服务器网卡的 MAC 锁定。这些端口级配置在 交换机管理 里填写,由系统按厂商指令集下发,不用逐台登录交换机。客户服务器上开放了哪些 UDP 服务,仍要在服务器防火墙和安全组里按上文逐项收紧。