- การพัฒนาของ 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)ที่ซับซ้อน ก็เป็นแรงผลักดันโดยตรงเช่นกัน
- ความต้องการจากงานจริงในการซัพพอร์ตลูกค้า OpenBSD ด้วยคอนฟิก
เหตุผลที่หวนกลับไปหา 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 ที่เหลือ
- Primary: https://rsadowski.gothub.org/
- Mirror: https://codeberg.org/rsadowski/relayd
- Mirror: https://github.com/sizeofvoid/relayd
- ใช้วิธีเดียวกันกับ
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-foldheader ด้วย 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 ความคิดเห็น
ความคิดเห็นจาก 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
https://i.ibb.co/V0BgWFbV/image.png
https://hypertekst.net/Screenshot.png