13 คะแนน โดย GN⁺ 2026-01-20 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • วันที่ 8 มกราคม 2026 อัปเดตบริการ 1.1.1.1 ของ Cloudflare ได้เปลี่ยนลำดับของเรคอร์ดภายในคำตอบ DNS ส่งผลให้ผู้ใช้บางส่วนทั่วโลกเกิด ความล้มเหลวในการแปลผล DNS
  • สาเหตุของปัญหาคือการเปลี่ยนโค้ดที่ทำให้ CNAME record ถูกย้ายไปไว้หลัง A/AAAA record ทำให้ การติดตั้งใช้งาน DNS client บางตัวพึ่งพาลำดับ
  • โดยเฉพาะ ฟังก์ชัน getaddrinfo ของ glibc และ โปรเซส DNSC ของสวิตช์ Cisco ได้รับผลกระทบ และในกรณีหลังถึงขั้นเกิด ลูปรีบูต
  • RFC 1034 ระบุเพียงว่า “CNAME อาจถูกวางนำหน้าได้ (possibly preface)” จึงทำให้ ไม่มีมาตรฐานที่ชัดเจนเกี่ยวกับลำดับของเรคอร์ด
  • Cloudflare ย้อนกลับไปใช้วิธีวาง CNAME ไว้ก่อนเสมอ และส่ง Internet-Draft ไปยัง IETF เพื่อกำหนดมาตรฐานที่ชัดเจน

1. ภาพรวมของเหตุการณ์

  • วันที่ 8 มกราคม 2026 มีการปล่อย อัปเดตเพื่อลดการใช้หน่วยความจำ ของ 1.1.1.1 ซึ่งทำให้เกิด การเปลี่ยนลำดับเรคอร์ด ภายในคำตอบ DNS
    • การเปลี่ยนแปลงถูกนำเข้าในโค้ดเบสเมื่อวันที่ 2 ธันวาคม 2025, ปล่อยสู่สภาพแวดล้อมทดสอบวันที่ 10 ธันวาคม และเริ่ม rollout ทั่วโลกวันที่ 7 มกราคม 2026
    • ประกาศเหตุขัดข้องเวลา 18:19 UTC ของวันที่ 8 มกราคม, เริ่ม rollback เวลา 18:27 และกู้คืนเสร็จเวลา 19:55
  • DNS client สมัยใหม่ส่วนใหญ่ ไม่สนใจลำดับของเรคอร์ดในคำตอบ แต่บาง implementation สมมติว่า CNAME ต้องมาก่อนเสมอ
  • เมื่อลำดับนี้เปลี่ยนไป client บางตัวจึง มองว่าคำตอบว่างเปล่า และทำให้การแปลผลล้มเหลว

2. CNAME chain และการทำงานของแคช

  • เมื่อมีการ query โดเมน เช่น www.example.com จะถูกแปลผลไปยัง IP ปลายทางผ่าน CNAME chain หลายชั้น
    • ตัวอย่าง: www.example.com → cdn.example.com → server.cdn-provider.com → 198.51.100.1
  • ลิงก์ CNAME แต่ละตัวมี TTL (Time-To-Live) และอาจหมดอายุเพียงบางส่วนได้
  • 1.1.1.1 จะ query ใหม่เฉพาะส่วนที่หมดอายุ แล้ว รวมแคชเดิมเข้ากับเรคอร์ดใหม่ เพื่อสร้างคำตอบ

3. รายละเอียดของการเปลี่ยนโค้ด

  • ในโค้ดเดิม จะ แทรก CNAME chain ก่อน แล้วจึงเพิ่ม A/AAAA record ตามหลัง
    • answer_rrs.extend_from_slice(&self.records); // CNAMEs first
  • ในโค้ดที่เปลี่ยนแล้ว จะ เพิ่ม CNAME เป็นลำดับสุดท้าย
    • entry.answer.extend(self.records); // CNAMEs last
  • ส่งผลให้ CNAME ถูกย้ายลงไปด้านล่างในคำตอบ และ client บางตัวไม่สามารถจัดการได้

4. ตัวอย่าง implementation ที่ได้รับผลกระทบ

  • ฟังก์ชัน getaddrinfo ของ glibc จะ parse คำตอบตามลำดับ และ ต้องเจอ CNAME ก่อน จึงจะติดตามชื่อถัดไปได้
    • หาก CNAME มาอยู่ด้านหลัง “ชื่อที่คาดหวัง” จะไม่ถูกอัปเดต ทำให้ผลลัพธ์ว่างเปล่า
  • โปรเซส DNSC ของ Cisco Catalyst switch 3 รุ่น ก็ได้รับผลกระทบเช่นกัน และหากใช้งาน 1.1.1.1 จะเกิด ข้อผิดพลาดร้ายแรงจนเข้าสู่ลูปรีบูต
    • Cisco ได้เผยแพร่ เอกสารบริการ ที่เกี่ยวข้อง

5. implementation ที่ไม่ได้รับผลกระทบ

  • systemd-resolved จะ parse คำตอบเป็น โครงสร้าง OrderedSet จึงสามารถค้นหาทั้งชุดได้โดยไม่ขึ้นกับตำแหน่งของ CNAME
    • ดังนั้นจึงยังทำงานได้ปกติแม้ลำดับเรคอร์ดจะเปลี่ยน

6. ความกำกวมของ RFC 1034

  • RFC 1034 (1987) ระบุว่า “คำตอบอาจถูก preface ด้วย CNAME อย่างน้อยหนึ่งรายการ”
    • แต่ไม่มีคีย์เวิร์ดเชิงบรรทัดฐานอย่าง MUST/SHOULD จึง ไม่ใช่ข้อกำหนดที่ระบุไว้อย่างชัดเจน
  • กว่าคีย์เวิร์ดลักษณะนี้จะถูกทำให้เป็นมาตรฐานก็ต้องรอถึง RFC 2119 (1997) ทำให้เอกสารในยุคนั้น ขาดถ้อยคำบังคับที่ชัดเจน
  • Cloudflare วาง CNAME ไว้ก่อนใน implementation แรกเริ่ม แต่ ไม่ได้รับประกันเรื่องนี้ด้วยการทดสอบ

7. ความแตกต่างระหว่าง RRset กับ message section

  • RFC 1034 §3.6 ระบุว่า ลำดับของ RRset (ชุดเรคอร์ดที่มีชื่อ ชนิด และคลาสเดียวกัน) ไม่มีความสำคัญ
  • แต่ไม่ได้กล่าวถึง ลำดับระหว่าง RRset คนละชุด
  • ตัวอย่างใน §6.2.1 ก็กล่าวถึงเพียง A record สองรายการของชื่อเดียวกัน และไม่ได้พูดถึงลำดับสัมพัทธ์ระหว่าง CNAME กับ A
  • ดังนั้น นิยามเรื่องลำดับระหว่าง CNAME กับ A record จึงยังเป็นช่องว่าง

8. ปัญหาลำดับภายใน CNAME chain

  • หาก CNAME มีหลายขั้น แม้ลำดับภายใน chain เองจะสลับกัน ก็อาจทำให้ การ parse แบบลำดับล้มเหลว
    • ตัวอย่าง: หาก cdn.example.com CNAME server.cdn-provider.com มาก่อน ก็จะหา www.example.com CNAME cdn.example.com ไม่เจอ
  • RFC 1034 ไม่ได้กำหนดข้อบังคับเกี่ยวกับลำดับของ CNAME chain เช่นกัน

9. เกณฑ์การทำงานของ resolver

  • RFC 1034 §5.2.2 ระบุว่า “เมื่อ resolver พบ CNAME จะต้อง เริ่ม query ใหม่ด้วยชื่อใหม่
  • แต่คำอธิบายนี้มุ่งไปที่ resolver เต็มรูปแบบ (เช่น 1.1.1.1) ขณะที่
    stub resolver อย่าง glibc ไม่ได้ implement logic นี้
  • ผลลัพธ์คือ stub resolver บางตัว ไม่ได้ทำงานตามพฤติกรรมที่ RFC คาดหวัง

10. เปรียบเทียบกับข้อกำหนดที่ชัดเจนของ DNSSEC

  • RFC 4035 (DNSSEC) ระบุด้วยคำว่า MUST ถึง ลำดับความสำคัญของการรวม RRSIG record
    • อย่างไรก็ตาม นี่เป็นข้อกำหนดเรื่อง “ต้องรวมไว้หรือไม่” ไม่ใช่เรื่อง “ลำดับ”
  • DNSSEC มี กฎเรื่องการรวมข้อมูลที่ชัดเจน แต่ใน unsigned zones ความกำกวมของ RFC 1034 ก็ยังคงอยู่

11. ข้อสรุปและมาตรการของ Cloudflare

  • แม้ตาม RFC แล้วลำดับของ CNAME จะ ไม่ใช่ข้อบังคับ แต่เนื่องจาก client บางตัว ตั้งสมมติฐานว่าต้องเป็นเช่นนั้น
    จึงย้อนกลับไปใช้นโยบาย วาง CNAME ไว้ก่อนเสมอ
  • เพื่อป้องกันปัญหาลักษณะเดียวกันในอนาคต ได้มีการ ส่ง Internet-Draft ไปยัง IETF
    • เอกสาร: draft-jabley-dnsop-ordered-answer-section
    • เป้าหมาย: ทำให้มาตรฐานเรื่องลำดับการจัดการ CNAME ในคำตอบ DNS ชัดเจนขึ้น
  • Cloudflare ระบุว่าเหตุการณ์นี้แสดงให้เห็นว่า ความกำกวมของโปรโตคอลที่มีอายุ 40 ปี ยังคงส่งผลต่อการใช้งานจริงในปัจจุบัน

12. ข้อมูลเพิ่มเติม

  • Cloudflare ให้บริการผ่าน Connectivity Cloud ซึ่งรวมถึง 1.1.1.1 เพื่อ
    ปกป้องเครือข่ายองค์กร, เร่งความเร็วแอปพลิเคชันระดับอินเทอร์เน็ต, ป้องกัน DDoS และ สนับสนุนการใช้งาน Zero Trust
  • แอปฟรี 1.1.1.1 ช่วยให้ เข้าถึงอินเทอร์เน็ตได้เร็วและปลอดภัยยิ่งขึ้น

1 ความคิดเห็น

 
GN⁺ 2026-01-20
ความคิดเห็นจาก Hacker News
  • ฉันรู้สึกว่าถ้อยคำใน RFC ไม่ได้กำกวมขนาดนั้น
    วลี “possibly preface” อ่านได้ว่า “ถ้ามี CNAME record ก็ให้ใส่มันไว้ก่อน” มากกว่า ไม่ได้หมายความว่า “ถ้าอยากจะใส่ไว้ตรงไหนก็ได้”

    • ฉันก็คิดแบบนั้น คำว่า “prefix ได้” ไม่ได้แปลว่า “suffix ก็ได้”
      แต่ประเด็นสำคัญไม่ใช่แค่การตีความประโยค แต่คือทีมที่ดูแล DNS server ที่สำคัญที่สุดตัวหนึ่งของโลก เปลี่ยน logic การตอบกลับ CNAME
      มันน่าจะพังในการทดสอบอย่างชัดเจน แต่กลับไม่มีใครถามว่า “ลำดับนี้สำคัญไหม?” ซึ่งน่าแปลกใจ
      ช่วงหลัง Cloudflare เปิดเผยปัญหาอย่างโปร่งใสดี แต่กรณีนี้ฟังดูเหมือน “มาแชร์เรื่องน่าสนใจ” มากกว่า
      การที่เรื่องแบบนี้ผ่านการทดสอบในระบบขนาดใหญ่ได้ ดูเป็นความผิดพลาดที่ค่อนข้างใหญ่
    • ในบทความอธิบายว่าความกำกวมมาจากอีกประโยคหนึ่ง — คือข้อความที่ว่า “ความแตกต่างของลำดับ RR ใน response section ไม่มีความสำคัญ”
      ตัวอย่างนั้นอาจถูกทำให้เป็นกฎทั่วไปได้ เลยมีช่องให้เข้าใจผิดว่า “ทุกกรณีลำดับไม่สำคัญ”
      สุดท้าย “ความเข้าใจที่ชัดเจน” ของคนหนึ่ง อาจดูเป็น “ได้อ่านเอกสารครบหรือเปล่า?” สำหรับอีกคน
      กรณีแบบนี้แสดงให้เห็นความสำคัญของ ภาษาบังคับเชิงมาตรฐาน (normative language)
    • คุณอาจรู้สึกว่ามันไม่กำกวม แต่ในความเป็นจริงมันกำกวม และก็มีความพยายามจะแก้ไขเรื่องนี้ด้วย
      ดูการถกเถียงที่เกี่ยวข้องได้ใน IETF mailing list
    • ฉันก็เห็นด้วยกับคุณ คิดว่ามีการตีความตัวอย่าง 6.2.1 ใน RFC ผิด
      คำว่า “ความต่างของลำดับไม่มีความสำคัญ” ใช้ได้เฉพาะกับตัวอย่างนั้น ไม่ได้หมายความว่าให้ละเลยกฎทั่วไป
      แม้ RFC 1034 จะบอกว่าได้กำหนด RRset ไว้ แต่จริง ๆ แล้วไม่มีการนิยามคำนี้ไว้
      การตีความของ Cloudflare ดูเหมือน เข้าใจข้อยกเว้นว่าเป็นกฎทั่วไป
      อย่างไรก็ตาม ยังไม่มีข้อกำหนดที่ชัดเจนเกี่ยวกับลำดับของ CNAME chain ดังนั้นในจุดนั้นก็ยังมีความกำกวมอยู่เล็กน้อย
    • ประเด็นนั้นก็ถูกกล่าวถึงในบทความแล้ว บทความชี้ให้เห็นว่า RFC เป็นเอกสารจากก่อนยุคที่ คำเชิงบังคับตามมาตรฐาน (MUST, SHOULD) ถูกทำให้เป็นมาตรฐาน
  • นี่ดูเหมือนเป็นกรณีที่ Hyrum’s Law กับ Postel’s Law ทำงานพร้อมกัน
    คือความคิดที่ว่า “ถ้ามีผู้ใช้ API มากพอ สักคนก็จะพึ่งพาพฤติกรรมทุกอย่างของระบบที่สังเกตได้”
    ปะทะกับหลักการ “ส่งอย่างระมัดระวัง รับอย่างยืดหยุ่น”

    • แต่ทุกวันนี้ก็มองกันมากขึ้นว่า Postel’s Law เป็น หลักการที่ก่อผลเสีย
    • ใช่ แต่แก่นของ Hyrum’s Law คือโลกนี้มี edge case จำนวนมหาศาล
      ประเด็นคราวนี้คือ resolver ของ glibc พัง — ซึ่งไม่ใช่สถานการณ์ที่หายากเลย
      ข่าวจริง ๆ คือ Cloudflare ทดสอบมาไม่ดีพอ
    • สุดท้ายแล้วนี่คือปัญหา leaky abstraction ในระดับมนุษย์
    • มี การ์ตูน xkcd ที่อธิบาย Hyrum’s Law ได้สมบูรณ์แบบ
  • บั๊กครั้งนี้ทำให้ฉันนึกถึงเรื่องเก่า ๆ
    ตอนปี 2011 ที่ Cloudflare เมิน RFC แล้ว ยอมให้ใช้ CNAME ที่ domain apex
    ถ้าอ่าน โพสต์บล็อกตอนนั้น จะเห็นทำนองว่า “จะเมิน RFC แล้วแก้ปัญหาในโลกจริง”
    แต่ CNAME เป็นแนวคิดระดับ ชื่อ(alias) ดังนั้นถ้าเอาไปไว้ที่ apex จะทำให้การแคช NS, MX, SOA พัง
    ตอนนั้นวิศวกรหลายคนเตือนแล้ว แต่บรรยากาศคือ “move fast and break things”
    ถึงอย่างนั้น รอบนี้เห็นว่าพวกเขาพูดถึงลำดับของ CNAME chain กับ A record อย่างละเอียด ก็ถือว่าพัฒนาขึ้น

    • เห็นด้วยกับคุณ สมัยก่อนใน BIND ฉันเห็น error “cannot have CNAME and other data” นับครั้งไม่ถ้วน
      แนวคิดเรื่อง CNAME กับ alias ทำให้สับสนมานานแล้ว และ ภาษาที่ไม่เป็นเชิงบังคับ ใน RFC1034 ก็ยิ่งเพิ่มความสับสน
      นี่เป็นผลสะสมของความกำกวมเหล่านั้น แต่ที่ผู้ให้บริการรายใหญ่ทำพลาดแบบนี้ ก็ยังยอมรับได้ยากอยู่ดี
    • แต่ถ้าตั้งใจฝ่าฝืนสเปก แบบนั้นจะเรียกว่า “บั๊ก” ได้จริงหรือ?
      ฉันกลับคิดว่า ตัวสเปกเองต่างหากที่เป็นปัญหา
  • น่าประหลาดใจที่ DNS lookup ทั่วไปของ glibc พึ่งพาลำดับของ record
    แปลกดีที่ไม่มีปัญหาใหญ่ตลอดมากว่า 20 ปี
    เป็นไปได้ว่าผู้ดูแล DNS ส่วนใหญ่น่าจะรู้จากประสบการณ์ระหว่างทดสอบว่า ลำดับนั้นสำคัญ

    • ปัญหาแบบนี้อาจเกิดบ่อยอยู่แล้ว แต่ใน บริการขนาดเล็ก คนก็คงปล่อยผ่านไป
      กรณีที่มันกระทบอุปกรณ์หลายล้านเครื่องทั่วโลกแบบ Cloudflare อาจเป็นครั้งแรก เลยถูกจับตามอง
      แต่ก็สงสัยว่า Cloudflare ได้ ส่งแพตช์ ไปยัง open source resolver อย่าง glibc หรือเปล่า
    • โดยทั่วไปฝั่งเซิร์ฟเวอร์จะคงลำดับไว้ และเซิร์ฟเวอร์ที่ไม่ทำแบบนั้นก็มักถูกแก้เร็วเพราะ ปัญหาความเข้ากันได้
      CNAME เป็นอะไรที่ รับมือยากจริง ๆ (บันทึกของ DJB น่าสนใจ)
    • อินเทอร์เน็ตจริง ๆ แล้วพึ่งพา implementation ของ authoritative server รายหลัก อยู่ไม่กี่ตัว และทุกเจ้าก็ใช้กฎเรื่องลำดับแบบเดียวกัน
    • ถ้าจะยกเลิกข้อจำกัดเรื่องลำดับ ก็ต้องมี โครงสร้างข้อมูลที่ค้นหา DNS name ได้รวดเร็ว
      resolver แบบง่ายอย่าง glibc ไม่มี cache ดังนั้นถ้าจะทำเรื่องนี้ให้ถูกต้อง ก็ต้องแก้โค้ดใหญ่พอสมควร
  • การที่ Cloudflare อ้างว่า “RFC ไม่ได้บังคับเรื่องลำดับของ CNAME” ฟังดูเหมือน เล่นคำตามตัวอักษร
    แค่ไม่มีคำว่า “MUST” ไม่ได้แปลว่า “จะเรียงลำดับยังไงก็ได้”
    ฉันคิดว่าการยอมรับว่าพลาดแล้วเดินหน้าต่อ จะทำให้โลกดีขึ้นกว่า
    การ หนีความรับผิดชอบด้วยการถกเถียงเรื่องถ้อยคำ มีแต่จะทำให้เสียความน่าเชื่อถือ

  • ดูเหมือน Cloudflare จะเข้าใจ RFC1034 ไม่ถูกต้อง
    อินเทอร์เฟซ DNS ของพวกเขาถ้ามี CNAME จะบล็อกแค่ A, AAAA แต่ยังอนุญาต record อื่น
    ทำให้เมื่อมี CNAME กับ TXT อยู่ร่วมกัน จะเกิดผลลัพธ์ที่ ขึ้นกับ cache
    internet.nl ก็พบปัญหาแบบนี้เหมือนกัน
    ผู้ใช้บางรายตั้งค่าตาม คู่มือของ mxtoolbox ซึ่งขัดกับ RFC1034

    • คู่มือนั้นน่าจะปนกันระหว่างคำอธิบายสองแบบ
      แบบหนึ่งคือ “วิธีมอบหมายบริการ DMARC ด้วย CNAME” อีกแบบคือ “วิธีโฮสต์เองโดยตรง”
      ดูเหมือนภาพหน้าจอจะทำให้คนสับสน
  • การที่ท้ายที่สุด Cloudflare สรุปว่า CNAME ควรมาก่อน record อื่น ถือว่าสมเหตุสมผล

    • ฉันก็ดีใจกับข้อสรุปนั้น ถึงทุกคนจะผิด แต่บางครั้งเราก็ต้อง ปรับให้เข้ากับความเป็นจริง
  • ตอนดูแล DNS ในบริษัท ฉันได้สัมผัสกับ ข้อจำกัดหลายอย่างของ DNS
    โดยเฉพาะเวลาเกิด SERVFAIL ฝั่ง client จะแยกไม่ออกว่าเซิร์ฟเวอร์ไหนมีปัญหา
    ผลคือ DNS server หลายตัวกับชั้น cache ต่าง ๆ จะทำ retry ถล่มโดยไม่จำเป็น
    อีกทั้ง search path ก็ทำให้เกิดคำขอ NXDOMAIN ซ้ำ ๆ ไปยังโดเมนที่ผิด

    • ฉันก็เคยเจอปัญหาคล้ายกัน มัวแต่ดู caching server อยู่เป็นวันกว่าจะเจอสาเหตุ สุดท้ายกลายเป็นปัญหาที่ auth server
    • ใน BIND 9 มี ตัวเลือก servfail-ttl ที่ช่วยบรรเทาเรื่องนี้
      ตาม RFC2308 section 7.1 อนุญาตให้แคชการตอบกลับ SERVFAIL ได้
      แม้จะเป็นมาตรฐานเก่า แต่ก็ยังเป็นแนวทางที่ใช้ได้อยู่
  • Cloudflare มักจะ ทำลายมาตรฐาน แล้วค่อย เขียน RFC ใหม่ มาอธิบายให้ดูสมเหตุสมผล
    กรณีอย่าง RFC 8482 ถือเป็น ความน่าอับอาย ของวงการในมุมมองฉัน
    คำพูดที่ว่า “ครั้งนี้ก็ยื่น Internet-Draft ใหม่เพื่อป้องกันความสับสน” ฟังดูประชดประชันดี

  • ถ้าเป็น DNS server ขนาดใหญ่อย่าง 1.1.1.1 ก็ควรมี integration test ที่รวม resolver จริงอย่าง glibc ด้วย
    แต่ก็สงสัยว่าทำไมปัญหาแบบนี้ถึงเพิ่งมา ถูกพบใน production

    • อาจเป็น การจับคู่ที่พบได้ยาก คือจะเกิดเฉพาะตอนลำดับการหมดอายุของ cache ซ้อนกันพอดี แล้วค่อยมีการ query ใหม่ผ่าน glibc
      การทดสอบแยกส่วนอาจผ่านหมด แต่กรณีที่สองเงื่อนไขมาชนกันอาจหลุดไป