Web開発
死せるソフトウェアの歩み: relayd(8)とhttpd(8)の継続的な進化
Dead Software Walking: The ongoing evolution of relayd(8) and httpd(8) (rsadowski.de)
要約
OpenBSDのrelayd(8)とhttpd(8)は、開発が停滞していましたが、著者が再びコーディングに挑戦したいという動機と実用的な必要性から、活発な開発が再開されました。著者はコードベースの理解、過去の課題への対応、そして貢献を容易にするためのミラーサイトの設置を進め、両デーモンの近代化、コード品質向上、セキュリティ強化、バグ修正、新機能追加といった具体的な成果をリストアップしています。
全文翻訳
目次
WHYから始めよう
OpenBSD 7.8のハイライト記事で触れたように、relayd(8)とhttpd(8)の開発は停滞していました。tech@メーリングリストには様々な貢献者から多くの差分(diff)が寄せられましたが、リポジトリにコミットされたのはごくわずかでした。主な理由は単純でした。既存のOpenBSD開発者はこれらのデーモンに興味を失っていたのです。勢いと言うべきか、タイミングと言うべきか。ほぼ同時期に、kirill@と私はこれらのデーモンにさらに積極的に取り組み始めました。私たちは両方ともそれらを日常的に使用しており、実際のユースケースがあります。私はOpenBSDセットアップのお客様をサポートしており、そこにはしばしば複雑なhttpd(8)とrelayd(8)の設定が含まれます。この実践的なニーズが、多くのレベルで私を動機づけました。しかし、最大の動機はLLM(大規模言語モデル)でした。長年、私はプロフェッショナルとしてモダンなC++コードを書いてきました。最終的には、開発業務から離れ、ソリューションアーキテクチャ、プラットフォームエンジニアリング、チーム構築に注力しました。ほとんど宣言的なYAMLしか書いていませんでした。私が書いた唯一のコーディングは、OpenBSDのports(7)のためにコードを読み、移植することでした。そしてLLMが登場しました。「コーディングは終わった」とテクノロジー界のインフルエンサーたちが主張する中で、私はあることに気づきました。もう一度自分自身にコーディングで挑戦したいと。この知識が外部委託されている時代だからこそ、それを保持することがこれまで以上に重要だと私は思います!Cは常に私を最も恐れさせてきた言語でした。C++やRustは難しい思考を肩代わりしてくれます。Cはそうではありません。まさに私が求めていたのは、そのような挑戦でした。そこで、relayd(8)とhttpd(8)に貢献することを決意しました。
「千回の戦いに勝つよりも、自己に打ち勝つ方が良い。」 – ブッダ
モチベーションよりも規律
このセクションは意図的にこのタイトルで書きました。私たちはオープンソースについて話しています。貢献するという決断を下したにもかかわらず、数週間後にフラストレーションで終わっていた可能性もありました。「なぜ私はこんなことをしているのだろう?」しかし、もうその段階は過ぎたと感じています。痛みは実際、心地よいのです。最初は、コードベースを受動的に読み、多くの部分に落胆しました。おそらくCコードの書き方なのでしょう。コメントの不足かもしれません。あるいは、一部に設計上の問題があるのかもしれません。まさにスパゲッティコード。あるいは、それは私自身の問題かもしれません。時間はそれを教えてくれるでしょう。私はいくつかのOpenBSDデーモンのメンテナーと話し合い、手作業で作られたimsgメッセージシステムを近代化することから始めることにしました。まずrelayd(8)に焦点を当てています。httpd(8)はその後になります。これに取り組むことは、コードベースを理解するための素晴らしい方法です。次のステップは、2024年から2026年までのtech@メーリングリストのアーカイブをすべて確認することでした。保留中のすべての差分と問題を収集しました。ほとんどの問題に対応できたと思います。もし何か未解決のものがあれば、連絡してください。relaydとhttpd(8)は元々Reyk Floeter(reyk@)によって開発されました。彼は現在OpenBSDから引退しています。彼の今後の活躍を願っています。ReykはGitHubのミラーも維持していました: https://github.com/reyk/relayd。そこでの古い問題も確認しました。すべてクローズ、修正、または関連性がなくなったものです。そのミラーが私に独自のミラーを作成するきっかけを与えました。新しく若い貢献者にとって、より簡単にしたかったのです。また、OpenBSDのメーリングリストを超えてコミュニティにリーチしたいとも思いました。また、CVSツリーのgitミラーも作業しています。(CVSと私は決して友達にはなれません。私はSVNでキャリアをスタートさせましたが、それはすでに十分苦痛でした。もうバージョン管理の苦痛はごめんです。)開発は主にGothubインスタンスで行われています。他の場所は同期されています:プライマリ: https://rsadowski.gothub.org/ ミラー: https://codeberg.org/rsadowski/relayd ミラー: https://github.com/sizeofvoid/relaydhttpd(8)についても同様です。必要なすべてを網羅した詳細なREADME.mdを作成しました。
httpd(8)とrelayd(8)での成果
すべては肯定的な結末を迎えるべきです。OpenBSDチームがhttpd(8)とrelayd(8)で達成したことを見てみましょう:
relayd(8)
近代化とコード品質
- imsgシステムを、新しい安全なゲッター(imsg_get_data, imsg_get_type, imsgbuf_get)を使用するように変換しました。
- imsgペイロード読み取り全体で適切なエラーハンドリングを追加しました。
- bgpdと連携して、ロギングとコメントを標準化し、一貫性を保ちました。
- コード構成を改善するため、HTTP開始行のロジックを専用の関数に移動しました。
- knfmtフォーマットを適切に適用しました。
セキュリティ改善
- デフォルトのTLS暗号スイートを「HIGH:!aNULL」から「secure」に変更しました。
- CA privsepエンジンにECDSAサポートを追加しました。
- HTTP 400レスポンスで重複したContent-Lengthヘッダーを拒否します。
- パーサーの差異を防ぐために、obs-foldヘッダーを拒否します(RFC 9112 5.2)。
- IDチェックを使用して、IMSG_CTL_PROCFDを親プロセスに制限します。
- 機密性の高いパスワードデータにはexplicit_bzeroを使用します。
バグ修正と安定性
- クラッシュを引き起こしていたrelaydのリロード競合状態を修正しました。
- 複数のメモリリーク(X509_dup, config_purge, tls_cfg)を削除しました。
- NULLチェックと境界テストを修正しました。
- OpenSSLエラーに対する適切なエラーハンドリングを追加しました。
- TLSエラー時にOpenSSLエラーキューをドレインします。
新機能
- MKCALENDAR HTTPメソッドのサポートを追加しました。
- 複数のリスナーでのTLSサポート。
- 複数の解決可能なアドレスのサポート。
- 証明書、キー、OCSPステープルの明示的なパスを設定します。
- HTTPヘルスチェック用のUser-Agentを設定します。
- ボディのないHTTPレスポンスを正しく処理します。
httpd(8)
近代化とコード品質
- relaydとの一貫性を保つため、proc.cを新しいimsg APIに変換しました。
- 将来の構成オプションで拡張しやすいように、トークン順序を改善しました。
- bgpdと連携してロギングを標準化しました。
- コードの冗長性と空の関数を削除しました。
- knfmtフォーマットを適切に適用しました。
- ビルトインロジックを専用の関数に移動しました。
セキュリティ改善
- デフォルトのTLS暗号スイートを「compat」から「secure」に変更しました。
- リクエストスマグリング攻撃を防ぐため、CL.TEリクエストフレーミングを拒否します。
- HTTP 400でobs-foldヘッダーを拒否します(RFC 9112 5.2)。
- 同時のContent-LengthとTransfer-Encodingヘッダーのエラー処理。
- 追加保護のため、起動時にランダムリリンクを行います。
- IDチェックを使用して、IMSG_CTL_PROCFDを親プロセスに制限します。
- サーバー識別情報をレスポンスから隠すための「no banner」オプションを追加しました。
バグ修正と安定性
- HTTPリクエストでのサフィックス範囲処理を修正しました。
- server_http_time()がGMT時刻を正しく出力するように修正しました。
- manual仕様に従ってtimegm(3)のエラーチェックを行います。
- チャンク転送エンコーディングを使用したアップロードを修正しました。
- location fcgiparamsが2回送信される問題を修正しました。
- dispatch_parentでの適切なエラーハンドリング。
- bufferevent経由でアボートレスポンスを正しくドレインします。
- データコピー前にreturn_uri_lenを検証します。
- scan-buildのデッドストアの検出を修正しました。
新機能
- カスタムHTTPヘッダーのサポートを追加しました。
- より良い構成継承のための、locationでのgzip_staticの継承。
- より多くのフラグオプションのために、サーバーフラグを64ビット整数に拡張しました。
- 静的ファイル用のキャッシュ制御を追加しました。
私の個人的なハイライトは太字で示されています。正直なところ、私のバックログは増えています。しかし、それは問題ありません。今年の残りがどうなるか見てみましょう。アイデアやフィードバックがあれば、ぜひ共有してください。どこで見つけられるかはご存知でしょう。