1 คะแนน โดย GN⁺ 2 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การพัฒนาของ relayd(8) และ httpd(8) ที่เคยหยุดนิ่งเพราะความสนใจจากนักพัฒนา OpenBSD เดิมลดลง กลับมาคึกคักอีกครั้งจากการมีส่วนร่วมของผู้ร่วมพัฒนาที่มีความต้องการใช้งานจริงในระบบปฏิบัติการจริง
  • จุดเริ่มต้นมาจากการตัดสินใจว่า ในยุคที่ LLM เข้ามาแทนความรู้ด้านการเขียนโค้ด ยิ่งต้อง เรียนรู้และลงมือกับ C ด้วยตนเอง จึงเริ่มจากการปรับปรุงระบบ imsg แบบทำมือของ relayd(8) ให้ทันสมัย
  • มีการสะสางแพตช์ที่ยังไม่ถูกรวมในเมลลิงลิสต์ tech@ ช่วงปี 2024~2026 และ issue เก่าใน GitHub mirror เดิมเป็นส่วนใหญ่ พร้อมจัดทำ Git mirror และ README สำหรับผู้ร่วมพัฒนาใหม่
  • relayd(8) ปรับปรุงทั้ง API ของ imsg ให้ปลอดภัยขึ้น เสริมความปลอดภัยของ TLS และการพาร์สคำขอ รวมถึงแก้ปัญหาการชนกันระหว่างรีโหลด ส่วน httpd(8) เพิ่ม การป้องกัน request smuggling, header แบบกำหนดเอง และการควบคุมแคชของไฟล์แบบสแตติก
  • ทั้งสองดีมอนได้พัฒนาขึ้นพร้อมกันในด้าน ความปลอดภัย ความเสถียร และความสามารถในการขยาย แต่ระหว่างทำงาน backlog ก็เพิ่มขึ้นด้วย จึงยังเปิดรับไอเดียและฟีดแบ็กอย่างต่อเนื่อง

เบื้องหลังการชุบชีวิตโปรเจกต์ที่หมดความสนใจ

  • อย่างที่กล่าวไว้ใน การเปลี่ยนแปลงสำคัญของ OpenBSD 7.8 การพัฒนาของ relayd(8) และ httpd(8) อยู่ในภาวะชะงักงัน
    • มีผู้ร่วมพัฒนาหลายคนส่งแพตช์เข้าเมลลิงลิสต์ tech@ แต่แทบไม่มีอะไรถูกนำเข้า repository
    • สาเหตุหลักคือ นักพัฒนา OpenBSD เดิมไม่ได้ให้ความสนใจกับสองดีมอนนี้อีกต่อไป
  • ผู้เขียนเริ่มพัฒนาอย่างจริงจังจากประสบการณ์ที่ใช้งานสองดีมอนนี้เป็นประจำร่วมกับ kirill@ และดูแลกรณีใช้งานจริง
    • ความต้องการจากงานจริงในการซัพพอร์ตลูกค้า OpenBSD ด้วยคอนฟิก httpd(8)·relayd(8) ที่ซับซ้อน ก็เป็นแรงผลักดันโดยตรงเช่นกัน

เหตุผลที่หวนกลับไปหา C ในยุค LLM

  • แรงกระตุ้นใหญ่ที่สุดคือ การมาถึงของ LLM
    • ในอดีตผู้เขียนเคยเขียนโค้ด C++ สมัยใหม่แบบเชี่ยวชาญ แต่หลังจากย้ายไปทำ solution architecture, platform engineering และการสร้างทีม ก็แทบไม่ได้เขียนโค้ดจริงอีก
    • ส่วนใหญ่เหลือเพียงการเขียน YAML เชิงประกาศ และอ่านกับพอร์ตโค้ดสำหรับ OpenBSD ports(7)
  • ผู้เขียนมองว่า ตรงกันข้ามกับคำกล่าวที่ว่า “การเขียนโค้ดถูกแก้ปัญหาไปแล้ว” ยิ่งเป็นยุคที่ความรู้ถูกฝากไว้นอกตัวมากขึ้น ก็ยิ่งสำคัญที่จะต้องมีความรู้นั้นด้วยตัวเอง
  • C++ และ Rust ช่วยตัดสินใจเรื่องยากบางส่วนแทนได้ แต่ C ไม่ได้ทำแบบนั้น จึงเลือกใช้จุดนี้เป็นความท้าทายและตัดสินใจมีส่วนร่วมกับ relayd(8) และ httpd(8)

ขับเคลื่อนการมีส่วนร่วมด้วยวินัยมากกว่าแรงจูงใจ

  • การมีส่วนร่วมในโอเพนซอร์สอาจจบลงด้วยความท้อแท้ภายในไม่กี่สัปดาห์ แต่ผู้เขียนผ่านช่วงเริ่มต้นอันยากลำบากมาได้ และเข้าสู่จังหวะที่ทำงานต่อเนื่องได้
  • ในช่วงแรกมีการอ่านโค้ดแบบรับสารเพียงอย่างเดียว และรู้สึกท้อกับหลายส่วน
    • สาเหตุมาจากคอมเมนต์ที่ไม่เพียงพอ การออกแบบบางจุดที่ไม่ดี และโค้ดที่พันกันซับซ้อน โดยยังไม่แน่ชัดว่าเป็นธรรมชาติของโค้ด C หรือเป็นเพราะประสบการณ์ส่วนตัวยังไม่มากพอ
  • หลังหารือกับผู้ดูแลดีมอนของ OpenBSD จึงตัดสินใจปรับปรุง ระบบข้อความ imsg ที่ทำขึ้นแบบแมนนวลให้ทันสมัย
    • เริ่มโฟกัสที่ relayd(8) ก่อน แล้วค่อยขยายไปยัง httpd(8)
    • งานปรับปรุงให้ทันสมัยนี้เองก็ถูกใช้เป็นวิธีทำความเข้าใจ codebase

สะสางแพตช์ที่ยังไม่ถูกรวมและ issue เก่า

  • มีการตรวจบันทึกของเมลลิงลิสต์ tech@ ช่วงปี 2024~2026 เพื่อรวบรวมแพตช์และ issue ที่ยังไม่ได้จัดการ และเชื่อว่าได้จัดการไปเกือบทั้งหมดแล้ว
  • สองดีมอนนี้เดิมพัฒนาโดย Reyk Floeter ซึ่งปัจจุบันเกษียณจาก OpenBSD แล้ว
  • ยังได้ตรวจ issue เก่าใน relayd GitHub mirror ที่ Reyk ดูแลไว้
    • ทุก issue ตอนนี้อยู่ในสถานะที่ปิดได้หรือแก้ไขได้ และบางส่วนก็ไม่ยังมีผลอีกต่อไป

Git mirror สำหรับผู้ร่วมพัฒนาใหม่

  • จากแนวคิดของ GitHub mirror เดิม ผู้เขียนได้สร้าง mirror แยกขึ้นมาเพื่อช่วยให้ผู้ร่วมพัฒนาใหม่และรุ่นเยาว์เริ่มต้นได้ง่ายขึ้น และสร้างจุดเชื่อมกับชุมชนนอกเมลลิงลิสต์ OpenBSD
  • ใช้ CVS tree เป็น Git mirror โดยทำการพัฒนาบน Gothub instance ก่อน แล้วซิงก์ไปยัง repository ที่เหลือ
  • ใช้วิธีเดียวกันกับ httpd(8) และเขียน README.md แบบละเอียดที่รวมข้อมูลที่จำเป็น

การปรับ relayd(8) ให้ทันสมัยและคุณภาพโค้ด

  • เปลี่ยนระบบ imsg ไปใช้ accessor ที่ปลอดภัยกว่าอย่าง imsg_get_data, imsg_get_type, imsgbuf_get
  • เพิ่ม การจัดการข้อผิดพลาด ที่เหมาะสมตลอดกระบวนการอ่าน payload ของ imsg
  • ทำให้ logging และคอมเมนต์เป็นมาตรฐานเดียวกับ bgpd
  • แยกการจัดการบรรทัดเริ่มต้นของ HTTP ออกเป็นฟังก์ชันเฉพาะเพื่อปรับปรุงโครงสร้างโค้ด
  • ใช้รูปแบบ knfmt

การเสริมความปลอดภัยของ relayd(8)

  • เปลี่ยน cipher suite TLS เริ่มต้นจาก HIGH:!aNULL เป็น secure
  • เพิ่ม การรองรับ ECDSA ให้กับเอนจินแยกสิทธิ์ของ CA (privsep)
  • ปฏิเสธ header Content-Length ที่ซ้ำกันด้วยการตอบกลับ HTTP 400
  • ไม่อนุญาต header obs-fold เพื่อป้องกันความแตกต่างของ parser ตาม RFC 9112 5.2
  • ตรวจสอบ process ID และจำกัด IMSG_CTL_PROCFD ไว้ที่ parent process
  • ใช้ explicit_bzero เพื่อล้างข้อมูลรหัสผ่านที่มีความอ่อนไหว

การแก้บั๊กและเพิ่มเสถียรภาพของ relayd(8)

  • แก้ race condition ระหว่างการรีโหลด ที่เคยทำให้เกิดการล่ม
  • ลบ memory leak หลายจุดที่เกี่ยวข้องกับ X509_dup, config_purge, tls_cfg
  • แก้การตรวจ NULL และการตรวจขอบเขต
  • เพิ่มการจัดการข้อผิดพลาดที่เหมาะสมเมื่อ OpenSSL ล้มเหลว
  • เปลี่ยนให้ล้าง OpenSSL error queue เมื่อ TLS ล้มเหลว

ฟีเจอร์ที่เพิ่มเข้ามาใน relayd(8)

  • รองรับเมธอด HTTP MKCALENDAR
  • สามารถใช้ TLS ได้บนหลาย listener
  • รองรับหลายที่อยู่ที่สามารถทำ name resolution ได้
  • สามารถกำหนดพาธของ certificate, key และ OCSP staple ได้อย่างชัดเจน
  • ตั้งค่า User-Agent สำหรับคำขอตรวจสอบสถานะ HTTP
  • จัดการ HTTP response ที่ไม่มี body ได้อย่างถูกต้อง

การปรับ httpd(8) ให้ทันสมัยและคุณภาพโค้ด

  • ย้าย proc.c ไปใช้ imsg API แบบใหม่เพื่อให้สอดคล้องกับ relayd(8)
  • เปลี่ยนลำดับ token เพื่อให้ขยาย configuration option ในอนาคตได้ง่ายขึ้น
  • ทำให้ logging เป็นมาตรฐานเดียวกับ bgpd
  • ลบโค้ดซ้ำและฟังก์ชันว่าง
  • ใช้รูปแบบ knfmt
  • แยกการจัดการฟังก์ชันในตัวออกเป็นฟังก์ชันเฉพาะ

การเสริมความปลอดภัยของ httpd(8)

  • เปลี่ยน cipher suite TLS เริ่มต้นจาก compat เป็น secure
  • ปฏิเสธ CL.TE request framing เพื่อป้องกันการโจมตีแบบ request smuggling
  • ตอบกลับ obs-fold header ด้วย HTTP 400 ตาม RFC 9112 5.2
  • หากมีทั้ง header Content-Length และ Transfer-Encoding พร้อมกัน จะถือเป็นข้อผิดพลาด
  • ทำการ relink แบบสุ่มตอนบูตเพื่อเพิ่มการป้องกัน
  • ตรวจสอบ process ID และจำกัด IMSG_CTL_PROCFD ไว้ที่ parent process
  • เพิ่มตัวเลือก no banner เพื่อซ่อนข้อมูลระบุตัวตนของเซิร์ฟเวอร์ใน response

การแก้บั๊กและเพิ่มเสถียรภาพของ httpd(8)

  • แก้การจัดการ suffix range ของคำขอ HTTP
  • แก้ให้ server_http_time() แสดงเวลา GMT ได้อย่างถูกต้อง
  • ตรวจสอบข้อผิดพลาดของ timegm(3) ตามที่คู่มือระบุ
  • แก้ปัญหาอัปโหลดที่ใช้ chunked transfer-encoding
  • แก้ไม่ให้ fcgiparams ของ location ถูกส่งซ้ำสองครั้ง
  • เพิ่มการจัดการข้อผิดพลาดที่เหมาะสมให้ dispatch_parent
  • เปลี่ยนให้ล้าง response ที่ถูกยกเลิกผ่าน bufferevent อย่างถูกต้อง
  • ลบการเก็บค่าที่ไม่จำเป็นซึ่ง scan-build พบ
  • ตรวจสอบ return_uri_len ก่อนคัดลอกข้อมูล

ฟีเจอร์ใหม่ของ httpd(8) และงานที่ยังเหลือ

  • รองรับ HTTP header แบบกำหนดเอง
  • ทำให้ location สามารถสืบทอด gzip-static ได้ เพื่อการสืบทอดคอนฟิกที่ดีกว่า
  • ขยาย server flag เป็นจำนวนเต็ม 64 บิต เพื่อรองรับตัวเลือก flag ได้มากขึ้น
  • เพิ่ม การควบคุมแคช สำหรับไฟล์แบบสแตติก
  • ยิ่งทำงานต่อ backlog ก็ยิ่งเพิ่มขึ้น และยังคงเปิดรับไอเดียกับฟีดแบ็กสำหรับการพัฒนาในอนาคต

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

 
GN⁺ 2 시간 전
ความคิดเห็นจาก Lobste.rs
  • ดีใจที่รองรับ HTTP header แบบกำหนดเอง เมื่อก่อนเพราะไม่มีฟีเจอร์นี้ เลยใช้ httpd แม้กับงานง่าย ๆ ไม่ได้ ตอนนี้รองรับแล้วถือว่าดีมาก

  • การพัฒนา relayd(8) และ httpd(8) ชะงักไป และมีผู้ร่วมพัฒนาหลายคนส่งแพตช์เข้า mailing list tech@ แต่แทบไม่ได้ถูกรวมเข้า repository เลย เหตุผลหลักคือเหล่านักพัฒนา OpenBSD เดิมไม่ได้สนใจ daemon เหล่านี้อีกแล้ว จึงรู้สึกขอบคุณที่มีคน รับช่วงดูแลต่อ

  • ใช้ซอฟต์แวร์ทั้งสองตัวเป็นประจำ เลยดีใจที่กลับมาถูกดูแลอย่างจริงจังอีกครั้ง ไม่รู้เลยว่าการพัฒนาชะงักไป
    ดูเหมือนว่าเพราะ โครงสร้างซอฟต์แวร์ที่เรียบง่าย จึงสามารถกลับมาเริ่มพัฒนาใหม่และใส่ฟีเจอร์กับการแก้ไขจำนวนมากได้โดยไม่ต้องมีทีมขนาดใหญ่

  • เคยสับสนกับตัวเลขท้ายชื่อซอฟต์แวร์อยู่พักหนึ่ง ก่อนจะรู้ว่ามันคือ หมายเลขหมวดของคู่มือ
    1 หมายถึงโปรแกรมที่รันได้และคำสั่งเชลล์, 2 หมายถึง system call, 3 หมายถึง library call, 4 หมายถึงไฟล์พิเศษ, 5 หมายถึงรูปแบบไฟล์และกฎเกณฑ์, 6 หมายถึงเกม, 7 หมายถึงอื่น ๆ, 8 หมายถึงคำสั่งดูแลระบบ และ 9 แบบไม่มาตรฐานหมายถึง kernel routine

    • ลองรัน man 1 man หรือแบบสั้น ๆ man man เพื่อดู man(1) ได้ โดยเฉพาะหน้า intro ต่าง ๆ ที่อยู่ใน SEE ALSO มีประโยชน์มาก
  • สงสัยว่าการปรับปรุงเหล่านี้จะถูกรวมอยู่ใน OpenBSD 8.0 หรือไม่

  • สงสัยว่าลิงก์นี้ตั้งใจทำให้อ่านได้จริงหรือเปล่า บน Firefox สำหรับ Android เห็นเป็นแบบนี้
    https://imgur.com/a/oTimS9R