Dead Software Walking: The ongoing evolution of relayd(8) and httpd(8)
摘要
作者 Rafael Sadowski 讲述自己因实际需求和挑战自我,重新参与 OpenBSD 中 relayd (8) 和 httpd (8) 的开发。他整理了 2024-2026 年邮件列表和 GitHub 上的旧问题,创建了镜像以吸引新贡献者,并详细列出了两个守护进程在现代化、安全加固、bug 修复和新功能方面的具体改进,包括拒绝请求走私、默认 TLS 密码套件切换、内存泄漏修复等。
荐读理由
正文列出的安全加固(如拒绝 CL.TE 请求走私、拒绝 obs-fold 头、默认 TLS 密码套件切换)是通用 Web 服务实践,可迁移到自建服务;同时 relayd/httpd 的持续演进属于系统工具的真实技术变化,但需自行提取,间接价值为主。
原文
Dead Software Walking: The ongoing evolution of relayd(8) and httpd(8)
30 July 2026·1020 words·5 mins· loading · loading ·

Author
Rafael Sadowski
Shut up and hack
Table of Contents
Table of Contents
Start with WHY
As I mentioned in my OpenBSD 7.8 highlights post, development of relayd(8) and httpd(8) had stalled. Many diffs appeared on the tech@ mailing list from different contributors, but few were committed into the repository. The main reason was simple: Established OpenBSD developers weren’t interested in these daemons anymore. Call it momentum, or timing.
Around the same time, kirill@ and I started working on these daemons more actively. We both use them regularly and have real-world use cases. I support customers with OpenBSD setups that often involve complex httpd(8) and relayd(8) configurations. This practical need motivated me on many levels.
But the biggest motivation is and was LLMs.
For many years, I wrote modern C++ code professionally. Eventually, I moved away from development work and focused on solution architecture, platform engineering, and building teams. I wrote little actual code, mostly declarative YAML. The only coding I did was reading and porting code for OpenBSD ports(7).
Then LLMs arrived. As tech bros claimed “coding is solved”. I realized something: I wanted to challenge myself to code again. I think that at a time when this knowledge is being outsourced, it’s more important than ever to have it! C has always been the language that intimidated me most. C++ and Rust handle the hard thinking for you. C doesn’t. That’s exactly what I wanted: that kind of challenge.
So I decided to start contributing to relayd(8) and httpd(8)().
It is better to conquer self than to win a thousand battles. – Buddha
Discipline beats motivation
I wrote this section with this title intentionally. We’re talking about open source. Even though I made the decision to contribute, it could have ended in frustration weeks later. “Why am I doing this to myself?“But I think I’m past that point now. The pain actually feels good.
At first, I read through the codebase passively and was discouraged by many parts. Maybe it’s just how C code is written. Maybe it’s the lack of comments. Maybe it’s poor design in places. Real spaghetti code. Or maybe it’s just me. Time will tell.
I talked to the some OpenBSD daemon maintainers and decided to start modernizing the handcrafted imsg message system. I’m focusing on relayd(8) first. httpd(8) will follow. Working on this is a great way to understand the codebase.
My next step was to go through the tech@ mailing list archives from 2024 to 2026. I collected all open diffs and issues. I think I’ve addressed most of them. If anyone has something pending, please reach out.
relayd and httpd(8) were originally developed by Reyk Floeter (reyk@). He is now retired from OpenBSD. I wish him all the best. Reyk also maintained a GitHub mirror: https://github.com/reyk/relayd. I went through the old issues there too. Everything can be closed, fixed, or is no longer relevant.
That mirror inspired me to create my own. I wanted to make it easier for new and young contributors. I also wanted to reach the community beyond the OpenBSD mailing lists. Also, I work on a git mirror of the CVS tree. (CVS and I will never be friends. I started my career with SVN, which was painful enough. No more version control pain.)
Development happens primarily on the Gothub instance. The other locations are kept in sync:
Primary: https://rsadowski.gothub.org/
Mirror: https://codeberg.org/rsadowski/relayd
Mirror: https://github.com/sizeofvoid/relayd
The same goes for httpd(8). I wrote a detailed README.md that covers everything you need to know.
Achievements in httpd(8) and relayd(8)
Everything should end on a positive note. Let’s look at what the OpenBSD team has accomplished in httpd(8) and relayd(8):
relayd(8)
Modernization and Code Quality
Converted the imsg system to use new safer getters (imsg_get_data, imsg_get_type, imsgbuf_get)
Added proper error handling throughout imsg payload reading
Standardized logging and comments with bgpd for consistency
Moved HTTP start line logic into dedicated functions for better code organization
Added proper knfmt formatting
Security Improvements
Switched default TLS cipher set from “HIGH:!aNULL” to “secure”
Added ECDSA support to the CA privsep engine
Reject duplicate Content-Length headers with HTTP 400 response
Reject obs-fold headers to prevent parser differentials (RFC 9112 5.2)
Restrict IMSG_CTL_PROCFD to parent process with ID checks
Use explicit_bzero for sensitive password data
Bug Fixes and Stability
Fixed relayd reload race condition that caused crashes
Removed multiple memory leaks (X509_dup, config_purge, tls_cfg)
Fixed NULL checks and bounds tests
Added proper error handling for OpenSSL failures
Drain OpenSSL error queue on TLS failures
New Features
Added support for MKCALENDAR HTTP method
Support for TLS with multiple listeners
Support for multiple resolvable addresses
Allow explicit paths for certificates, keys and OCSP staples
Set User-Agent for HTTP healthchecks
Handle HTTP responses without bodies correctly
httpd(8)
Modernization and Code Quality
Converted proc.c to new imsg API for consistency with relayd
Made token order more easily extendable for future configuration options
Standardized logging with bgpd
Removed code redundancy and empty functions
Added proper knfmt formatting
Move builtin logic into dedicated function
Security Improvements
Switched default TLS cipher set from “compat” to “secure”
Reject CL.TE request framing to prevent request smuggling attacks
Reject obs-fold headers with HTTP 400 (RFC 9112 5.2)
Error out on simultaneous Content-Length and Transfer-Encoding headers
Random-relink at boot time for additional protection
Restrict IMSG_CTL_PROCFD to parent process with ID checks
Add “no banner” option to hide server identification from responses
Bug Fixes and Stability
Fixed suffix range handling in HTTP requests
Fixed server_http_time() to emit GMT times correctly
Error check timegm(3) per manual specifications
Fixed uploads using chunked transfer-encoding
Fixed location fcgiparams being sent twice
Proper error handling in dispatch_parent
Drain abort responses via bufferevent correctly
Fixed scan-build dead stores findings
Validate return_uri_len before copying data
New Features
Add custom HTTP header support
Inherit gzip-static in locations for better configuration inheritance
Widen server flags to 64-bit integers for more flag options
Add cache controls for static files
My personal highlights are in bold.
Honestly, my backlog has grown. But that’s fine. Let’s see where the rest of the year takes us. If you have ideas or feedback, please share them. You know where to find us.
↑
这条对你有帮助吗?