UDP 協議是什麼?特點、報文格式與適用場景
UDP 全稱 User Datagram Protocol(使用者資料包協議),由 RFC 768 定義,是 TCP/IP 傳輸層的兩大協議之一,IP 協議號為 17。它不建立連線、不確認、不重傳、不保證順序,首部只有源連接埠、目的連接埠、長度、校驗和 4 個欄位共 8 位元組,換來低延遲和低開銷,DNS、DHCP、NTP、SNMP、音影片和 HTTP/3 都建立在它之上。
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 服務,仍要在伺服器防火牆和安全組裡按上文逐項收緊。
常見問題
UDP 一個包最多能裝多少資料?
IPv4 包的總長度上限是 65535 位元組,扣掉 20 位元組 IPv4 首部和 8 位元組 UDP 首部,單個 UDP 資料包最多攜帶 65507 位元組;IPv6 的載荷長度不含 40 位元組首部,上限是 65527 位元組。超過鏈路 MTU 就要 IP 分片,在常見的 1500 位元組 MTU 上,不分片能裝下的資料是 1472 位元組(IPv4)。
HTTP/3 為什麼改用 UDP?
HTTP/3 執行在 QUIC 上,QUIC 基於 UDP,在使用者態自己實現可靠傳輸、擁塞控制和加密,避免了 TCP 一個包丟失就阻塞整條連線上所有請求的問題,建連也更快。QUIC 用連線 ID 而不是 IP 和連接埠識別連線,手機在 Wi-Fi 和行動網路之間切換時,連線不必重建。
UDP 不可靠,為什麼 DNS 還用它?
DNS 的查詢和應答通常各只有一個包,丟了由客戶端超時重發即可,代價比每次查詢先做三次握手小得多。應答太大裝不下時,伺服器在應答裡置截斷標誌,客戶端再改用 TCP 重新查詢。