- Ngày 8/1/2026, bản cập nhật dịch vụ 1.1.1.1 của Cloudflare đã thay đổi thứ tự bản ghi trong phản hồi DNS, khiến một số người dùng trên toàn thế giới gặp lỗi phân giải DNS
- Nguyên nhân là do thay đổi mã nguồn khiến bản ghi CNAME bị chuyển xuống sau bản ghi A/AAAA, trong khi một số triển khai client DNS phụ thuộc vào thứ tự
- Cụ thể, hàm
getaddrinfo của glibc và tiến trình DNSC trên switch Cisco bị ảnh hưởng; ở trường hợp sau còn dẫn tới vòng lặp khởi động lại
- RFC 1034 chỉ nêu rằng “CNAME có thể đứng trước (possibly preface)”, nên không có tiêu chuẩn rõ ràng về thứ tự bản ghi
- Cloudflare đã quay lại cách luôn đặt CNAME lên trước và gửi Internet-Draft lên IETF để định nghĩa tiêu chuẩn rõ ràng hơn
1. Tổng quan sự cố
- Ngày 8/1/2026, khi bản cập nhật giảm mức sử dụng bộ nhớ của 1.1.1.1 được triển khai, đã xảy ra thay đổi thứ tự bản ghi trong phản hồi DNS
- Thay đổi này được đưa vào codebase ngày 2/12/2025, triển khai ở môi trường thử nghiệm ngày 10/12, và bắt đầu phát hành toàn cầu ngày 7/1/2026
- Sự cố được tuyên bố lúc 18:19 UTC ngày 8/1, bắt đầu rollback lúc 18:27, và khôi phục hoàn tất lúc 19:55
- Phần lớn client DNS hiện đại bỏ qua thứ tự bản ghi trong phản hồi, nhưng một số triển khai giả định rằng CNAME phải luôn xuất hiện trước
- Khi thứ tự này thay đổi, một số client xử lý phản hồi như thể trống rỗng, dẫn đến lỗi phân giải
2. Chuỗi CNAME và cách hoạt động của cache
- Khi truy vấn tên miền, ví dụ
www.example.com, nó sẽ được phân giải tới IP cuối cùng thông qua nhiều chuỗi CNAME
- Ví dụ:
www.example.com → cdn.example.com → server.cdn-provider.com → 198.51.100.1
- Mỗi mắt xích CNAME đều có TTL (Time-To-Live), và chỉ một phần có thể hết hạn
- 1.1.1.1 chỉ truy vấn lại phần đã hết hạn, rồi gộp cache hiện có với bản ghi mới để tạo phản hồi
3. Chi tiết thay đổi mã nguồn
- Trong mã cũ, chuỗi CNAME được chèn trước, sau đó mới thêm bản ghi A/AAAA
answer_rrs.extend_from_slice(&self.records); // CNAMEs first
- Trong mã đã thay đổi, CNAME được thêm vào sau cùng
entry.answer.extend(self.records); // CNAMEs last
- Vì vậy, trong phản hồi, CNAME bị đẩy xuống phía dưới, khiến một số client không thể xử lý
4. Các trường hợp triển khai bị ảnh hưởng
- Hàm
getaddrinfo của glibc phân tích phản hồi theo trình tự và cần CNAME xuất hiện trước thì mới lần theo tên tiếp theo được
- Nếu CNAME đứng sau, “tên được kỳ vọng” không được cập nhật nên kết quả trở thành rỗng
- Tiến trình DNSC trên 3 mẫu switch Cisco Catalyst cũng bị ảnh hưởng; khi dùng 1.1.1.1 thì xảy ra lỗi nghiêm trọng dẫn đến vòng lặp khởi động lại
- Cisco đã công bố tài liệu dịch vụ liên quan
5. Các triển khai không bị ảnh hưởng
- systemd-resolved phân tích phản hồi bằng cấu trúc
OrderedSet, nên có thể duyệt toàn bộ tập hợp bất kể vị trí của CNAME
- Vì vậy nó vẫn hoạt động bình thường dù thứ tự bản ghi thay đổi
6. Tính mơ hồ của RFC 1034
- RFC 1034 (1987) mô tả rằng “phản hồi có thể được mở đầu bằng một hoặc nhiều CNAME”
- Tuy nhiên, không có từ khóa quy phạm như MUST/SHOULD, nên đây không phải yêu cầu tường minh
- Chỉ tới RFC 2119 (1997), các từ khóa như vậy mới được chuẩn hóa, nên tài liệu thời đó thiếu cách diễn đạt nghĩa vụ rõ ràng
- Cloudflare ban đầu đặt CNAME lên trước trong triển khai của mình, nhưng không có bài kiểm thử nào đảm bảo điều đó
7. Phân biệt RRset và phần message
- RFC 1034 §3.6 nêu rõ thứ tự trong RRset (tập các bản ghi có cùng tên, kiểu và lớp) là không quan trọng
- Tuy nhiên, nó không đề cập đến thứ tự giữa các RRset khác nhau
- Ví dụ trong §6.2.1 cũng chỉ xử lý hai bản ghi A cùng tên, chứ không bàn về thứ tự tương đối giữa CNAME và A
- Vì vậy, định nghĩa về thứ tự giữa CNAME và bản ghi A vẫn bị bỏ trống
8. Vấn đề thứ tự bên trong chuỗi CNAME
- Nếu CNAME có nhiều tầng, chỉ riêng việc chuỗi bị xáo trộn thứ tự cũng có thể khiến quá trình phân tích tuần tự thất bại
- Ví dụ: nếu
cdn.example.com CNAME server.cdn-provider.com xuất hiện trước, thì sẽ không tìm thấy www.example.com CNAME cdn.example.com
- RFC 1034 cũng không có yêu cầu nào về thứ tự trong chuỗi CNAME
9. Tiêu chí hoạt động của resolver
- RFC 1034 §5.2.2 quy định rằng “khi resolver gặp CNAME, nó phải khởi động lại truy vấn với tên mới”
- Tuy nhiên, mô tả này áp dụng cho resolver đầy đủ (ví dụ 1.1.1.1), còn
stub resolver như glibc thì không triển khai logic đó
- Kết quả là một số stub resolver không tuân theo hành vi được RFC kỳ vọng
10. So sánh với quy định tường minh của DNSSEC
- RFC 4035 (DNSSEC) quy định bằng từ MUST về ưu tiên bao gồm bản ghi RRSIG
- Tuy nhiên, đây là quy định về “có bao gồm hay không”, chứ không phải về thứ tự
- DNSSEC cung cấp quy tắc bao gồm rõ ràng, nhưng với unsigned zones thì tính mơ hồ của RFC 1034 vẫn còn nguyên
11. Kết luận và biện pháp của Cloudflare
- Dù theo RFC thì thứ tự CNAME không bắt buộc, một số client vẫn mặc định như vậy, nên
Cloudflare đã quay lại chính sách luôn đặt CNAME lên trước
- Để ngăn vấn đề tương tự tái diễn, Cloudflare sẽ gửi Internet-Draft lên IETF
- Qua sự cố này, Cloudflare xác nhận rằng sự mơ hồ của một giao thức 40 năm tuổi vẫn tiếp tục ảnh hưởng đến thực tiễn vận hành
12. Thông tin bổ sung
- Thông qua Connectivity Cloud, bao gồm cả 1.1.1.1, Cloudflare cung cấp
bảo vệ mạng doanh nghiệp, tăng tốc ứng dụng ở quy mô Internet, phòng vệ DDoS và hỗ trợ triển khai Zero Trust
- Với ứng dụng miễn phí 1.1.1.1, người dùng có thể truy cập Internet nhanh hơn và an toàn hơn
1 bình luận
Ý kiến trên Hacker News
Tôi thấy câu chữ trong RFC không hề mơ hồ đến vậy
Cụm “possibly preface” được hiểu là “nếu có bản ghi CNAME thì gắn nó lên trước”, chứ không thể diễn giải thành “thích đặt ở đâu cũng được”
Nhưng đây không chỉ là vấn đề diễn giải câu chữ, mà mấu chốt là đội đang vận hành một trong những máy chủ DNS quan trọng nhất thế giới đã thay đổi logic phản hồi CNAME
Chuyện này hẳn phải làm hỏng test rất rõ ràng, nên thật ngạc nhiên là không ai hỏi “thứ tự này có quan trọng không?”
Gần đây Cloudflare khá minh bạch khi công khai sự cố, nhưng vụ này lại giống kiểu “chia sẻ một sự thật thú vị” hơn
Việc thứ như thế này vượt qua được kiểm thử trong một hệ thống quy mô lớn có vẻ là một sai sót khá nghiêm trọng
Ví dụ đó có thể bị khái quát hóa, nên dễ bị hiểu nhầm thành “trong mọi trường hợp thứ tự đều không quan trọng”
Cuối cùng, điều một người xem là “hiểu rất rõ” có thể lại khiến người khác nghĩ “đã đọc hết tài liệu chưa?”
Những trường hợp như vậy cho thấy tầm quan trọng của ngôn ngữ quy phạm (normative language)
Có thể xem thảo luận liên quan trên mailing list IETF
Câu “khác biệt về thứ tự không quan trọng” chỉ áp dụng cho ví dụ cụ thể đó, chứ không phải bảo bỏ qua quy tắc chung
Dù RFC 1034 được nói là đã định nghĩa RRset, thực tế lại không hề có định nghĩa thuật ngữ đó
Cách hiểu của Cloudflare trông giống như nhầm một điều khoản ngoại lệ thành quy tắc chung
Tuy vậy, vẫn chưa có quy định thật rõ về thứ tự trong chuỗi CNAME, nên ở điểm đó vẫn còn chút mơ hồ
Đây có vẻ là trường hợp Hyrum’s Law và Postel’s Law cùng lúc phát huy tác dụng
Một bên là “nếu API có đủ nhiều người dùng, sẽ có ai đó phụ thuộc vào mọi hành vi quan sát được của hệ thống”, còn một bên là
“hãy bảo thủ ở thứ mình gửi đi, và khoan dung với thứ mình nhận vào”, và hai nguyên tắc đó đã va chạm với nhau
Điểm đáng chú ý lần này là resolver của glibc đã bị hỏng — hoàn toàn không phải tình huống hiếm gặp
Tin tức thật sự là Cloudflare đã không test cho tử tế
Lỗi này làm tôi nhớ lại một chuyện cũ
Năm 2011, khi Cloudflare phớt lờ RFC và cho phép CNAME ở domain apex
Bài blog khi đó cho thấy họ nói kiểu “mặc kệ RFC, chúng tôi sẽ giải quyết vấn đề thực tế”
Nhưng CNAME là khái niệm ở cấp tên (alias), nên đặt ở apex sẽ làm hỏng việc cache NS, MX, SOA
Khi đó nhiều kỹ sư đã cảnh báo, nhưng tinh thần là “move fast and break things”
Dù vậy, lần này thấy họ bàn khá kỹ về chuỗi CNAME và thứ tự bản ghi cũng cho thấy đã có tiến bộ
CNAME và khái niệm alias từ lâu đã gây nhầm lẫn, và ngôn ngữ phi quy phạm trong RFC1034 càng làm sự nhầm lẫn đó trầm trọng hơn
Đây là kết quả của sự mơ hồ tích tụ, nhưng một nhà cung cấp dịch vụ lớn vẫn mắc lỗi như vậy thì vẫn khó chấp nhận
Theo tôi thì chính đặc tả mới là vấn đề
Thật đáng ngạc nhiên là tra cứu DNS thông thường của glibc lại phụ thuộc vào thứ tự bản ghi
Việc hơn 20 năm qua không có vấn đề lớn nào xảy ra mới là điều lạ
Có lẽ phần lớn nhà vận hành DNS đã học được từ kinh nghiệm rằng thứ tự quan trọng trong lúc test
Trường hợp của Cloudflare được chú ý vì lần đầu ảnh hưởng đến hàng triệu thiết bị trên toàn thế giới
Tuy nhiên, tôi cũng tò mò không biết lần này Cloudflare có gửi patch cho các resolver mã nguồn mở như glibc hay không
CNAME thật sự là một thứ rất khó xử lý (xem ghi chú của DJB)
Những resolver đơn giản như glibc không có cache, nên để làm được điều đó sẽ cần thay đổi mã rất lớn
Việc Cloudflare khẳng định “RFC không yêu cầu thứ tự CNAME” nghe giống bắt bẻ câu chữ
Không có “MUST” không có nghĩa là “thứ tự nào cũng được”
Tôi nghĩ thừa nhận sai sót rồi bước tiếp sẽ khiến thế giới tốt hơn
Trốn tránh trách nhiệm bằng tranh cãi ngôn từ chỉ càng làm mất niềm tin
Có vẻ Cloudflare đã không hiểu đúng RFC1034
Giao diện DNS của họ chặn A, AAAA khi có CNAME, nhưng lại cho phép các bản ghi khác
Vì vậy khi CNAME và TXT cùng tồn tại thì sẽ xuất hiện kết quả phụ thuộc vào cache
internet.nl cũng đã phát hiện loại vấn đề này
Một số người dùng còn cấu hình theo hướng dẫn của mxtoolbox, vốn mâu thuẫn với RFC1034
Một là “cách ủy quyền dịch vụ DMARC bằng CNAME”, hai là “cách tự host trực tiếp”
Có vẻ chính ảnh chụp màn hình đã gây hiểu lầm
Việc Cloudflare cuối cùng đi đến kết luận rằng “CNAME phải đứng trước các bản ghi khác” là hợp lý
Khi quản lý DNS ở công ty, tôi đã cảm nhận rất rõ nhiều giới hạn của DNS
Đặc biệt là khi xảy ra SERVFAIL, client không thể phân biệt máy chủ nào đang có vấn đề
Kết quả là nhiều máy chủ DNS và các lớp cache tạo ra cơn bão retry không cần thiết
Ngoài ra, search path còn liên tục tạo truy vấn NXDOMAIN tới các domain sai
Theo RFC2308 mục 7.1, việc cache phản hồi SERVFAIL là được phép
Đây là một tiêu chuẩn cũ nhưng vẫn là cách tiếp cận còn hiệu lực
Cloudflare thường xuyên phá chuẩn, rồi lại viết RFC mới để biện minh cho việc đó
Những trường hợp như RFC 8482 theo tôi là nỗi hổ thẹn của cả ngành
Câu “lần này họ còn nộp Internet-Draft mới để tránh nhầm lẫn” nghe khá mỉa mai
Với một máy chủ DNS quy mô lớn như 1.1.1.1, đáng lẽ phải có kiểm thử tích hợp bao gồm cả các resolver thực tế như glibc
Vậy mà tại sao vấn đề này lại chỉ được phát hiện trong production thì thật khó hiểu
Các bài test riêng lẻ đều qua, nhưng trường hợp hai điều kiện chồng lên nhau thì đã bị bỏ sót