Category
C++26でネットワークプログラミング
C++26のstd::span、std::expectedなどのエルゴノミクスを使い、L2から上位のネットワークスタックを軽微に実装します。
15件の記事
TLS 1.3のFinished検証と送信——トランスクリプトハッシュとハンドシェイクの完了
復号したEncryptedExtensions以降のメッセージを読み進め、サーバのFinishedを検証してからクライアント自身のFinishedを送り返すところまでを実装します。動的に積み上がるトランスクリプトハッシュの扱いと、Finishedメッセージ特有の鍵導出を扱います。
続きを読むTLS 1.3のハンドシェイクレコード復号——AEAD鍵導出とTLSInnerPlaintextの復元
EncryptedExtensions以降のTLS 1.3ハンドシェイクメッセージはAES-128-GCMで保護されています。Handshake Traffic SecretからAEAD鍵/IVを導出し、レコードごとのnonce構成、TLSInnerPlaintextの復元、そして実サーバとの通信で必須になるChangeCipherSpecレコードの扱いまでを実装します。
続きを読むTLS 1.3のHandshake Traffic Secret導出——X25519共有鍵とHKDF鍵スケジュールの実装
TLS 1.3のEncryptedExtensions以降を暗号化するために必要なHandshake Traffic Secretを導出します。X25519のECDH共有鍵計算、RFC 8446 §7.1のHKDF-Extract/Expand-Label/Derive-Secretによる鍵スケジュールの実装、そしてRFC 8448の実例トレースを使って実サーバなしに導出結果を検証する方法までを扱います。
続きを読むTLS 1.3のClientHello構築とServerHello検証、OpenSSLでのX25519鍵ペア生成
TLS 1.3ハンドシェイクの最初の往復、ClientHelloの送信とServerHelloの受信・検証を実装します。鍵交換グループはX25519のみ、暗号スイートはTLS_AES_128_GCM_SHA256のみに絞り、鍵ペア生成だけOpenSSLの力を借ります。TLSレコードとは別の層であるハンドシェイクメッセージのフレーミングと、ServerHelloがHelloRetryRequestを兼ねる仕組みについても扱います。
続きを読むTLS 1.3レコード層のフレーミング実装と、TCPストリームからのレコード境界復元
TLS 1.3のレコード層のうち、暗号化を伴わないTLSPlaintextのフレーミング(RFC 8446 §5.1)を実装します。TCPはメッセージ境界を保持しないため、最大16384バイトのレコードを512バイト単位のTCPセグメントの連なりから正しく復元する`RecordLayer`の設計と、複数セグメントに渡る転送で表面化したTCP側の弱点についても扱います。
続きを読む簡易TCPのシーケンス番号・再送・フロー制御と、自作TCPクライアントが踏む「自分のカーネルのRST」問題
TCPヘッダのparse/buildの上に、stop-and-wait方式によるシーケンス番号管理・タイムアウト再送・簡易フロー制御を実装します。合わせて、OSの標準ソケットAPIを経由せず生ソケットで自前のTCPコネクションを実装したときに必ず踏む、「送信元マシン自身のカーネルが身に覚えのないセグメントへRSTを送り返してしまう」という設計上の制約と、その回避方法についても扱います。
続きを読むTCPヘッダのパース/構築と、3-wayハンドシェイクの実装
TCPヘッダはICMP/UDPと違い、フラグ・シーケンス番号・可変長のオプションを持ちます。3-wayハンドシェイクに必要な範囲でヘッダの型を設計し、UDPと同じ疑似ヘッダ方式のチェックサムを再利用しつつ、UDPには存在する「0はチェックサム未使用」という読み替えがTCPには不要である理由にも触れます。最後に、実際にLAN上のホストとSYN/SYN-ACK/ACKを交わすところまで確認します。
続きを読むUDPデータグラムのパース/構築と、疑似ヘッダによるチェックサム
UDPヘッダの`parse`/`build`を`std::expected`で設計します。ICMPと違い、UDPのチェックサムはヘッダ+ペイロードだけでなくIPv4ヘッダの一部を仮想的に含めた「疑似ヘッダ」を対象に計算する必要があります。あわせて、この1の補数和チェックサムが持つ検出限界(16bitワードの入れ替えを検出できない)にも触れます。
続きを読むICMP Echo Request/Replyのパースとバイト変換ヘルパーの共通化
ping応答/送信に必要なICMP Echo Request/Replyのパース・構築を`std::expected`と`std::vector<std::byte>`で実装し、IPv4ヘッダとの違い(チェックサムが可変長のデータ部まで含む点)と、複数ファイルで重複していた16bit読み書きヘルパーを内部ヘッダに切り出した設計を整理します。
続きを読むIPv4ヘッダをパースしてチェックサムを検証する
IPv4ヘッダを`std::expected`でパースし、インターネットチェックサムを検証する`parse_ipv4_packet`の設計です。1の補数和による検証トリックと、RFCの「Type of Service」オクテットが現在はDSCP/ECNとして再定義されているポイントを扱います。
続きを読むARP requestを実際に送ってIPアドレスをMACアドレスに解決する
指定したIPアドレスに対してARP requestを送信し、返ってきたreplyからMACアドレスを解決する`arp_resolve`を実装しました。Ethernetヘッダを手で組み立てる方法、ioctlでローカルのMAC/IPを取得する方法、そして「本当に待っていたreplyか」を見極める必要がある理由を扱います。
続きを読むIP→MAC対応をキャッシュするArpCacheとTTL設計
ARPで解決したIP→MAC対応をキャッシュする`ArpCache`を実装しました。std::unordered_mapに独自のハッシュ関数を渡す方法、TTLの期限切れをsleepなしでテストする方法、そして実機のARPトラフィックでTTL失効を確認するところまでをまとめます。
続きを読むAF_PACKET raw socketによるL2フレームキャプチャの実装
AF_PACKET raw socketでNICからEthernetフレームを直接送受信する`RawSocket`を実装しました。OSリソースの所有権をクラスとして表現する設計判断と、実機で実際のARPトラフィックを観測した結果までをまとめます。
続きを読むARPパケットの解析とバイト列の組み立て
ARPパケットのヘッダ構造をパースし、Request/Replyそれぞれのバイト列を組み立てる実装を行いました。エラー型をどう分割するか、パースと組み立てをラウンドトリップでテストする設計判断を整理します。
続きを読むstd::span/std::expectedで設計するEthernet IIフレーム解析
C++26対応のGCC 15と、std::span・std::expectedを使ってEthernet IIフレームのヘッダ解析を実装しました。生バイト列をコピーせずに扱う設計や、コンパイル時にサイズを保証するstd::spanの使い方、失敗をどこでどう表現するかという判断を整理します。
続きを読む