プロトコル演習: バイト列と届かない応答を説明する
ラボの前提: 所有するUbuntu Server 24.04 LTSまたはRocky Linux 9ゲスト。オフライン分析と、上限を設けたループバック通信を実施します。
最終更新日: September 15, 2026
目的と参加条件
エキスパートレベルのプロトコル調査では、アプリケーションの主張を特定の通信に結び付け、証拠だけでは何を立証できないかを明確にします。 このワークブックでは、プローブ照合台帳、HTTP/TCPの証拠一式、プロトコル境界のレポートを作成します。 これは独自の演習であり、採点対象となる大学課題の解答ではありません。
まず、復元操作と最後のサービス診断を含む初級編の8レッスンを完了してください。 アドレス、ネクストホップ、DNS応答、待ち受けソケット、HTTPステータスを区別できる必要があります。 基本的なPythonの読み取り、バイト/16進表記の理解、2つのファイルの比較も必要です。
証拠を集める前に、次の既存ガイドを読んでください。
- IP、ICMP、traceroute: エラーの送信元と、エラーに引用されたパケットを特定する。
- TCPとTLS: トランスポートによる配送と認証を区別する。
- HTTP/1.1メッセージの構造: ヘッダーの終端とコンテンツのバイト数を特定する。
- Linuxネットワーク診断: 既存の上限付きHTTPヘルパーと記録済みルーティング演習を理解する。
公開カリキュラムの案内
利用可能状況は2026年9月15日に確認しました。 2026年秋学期CS168のサイトは準備中です。 以下の順序で読むには、閲覧可能な2026年夏学期の公式アーカイブを使用してください。掲載日程は過去のものです。 公開ドキュメントが閲覧できても、履修登録、すべての録画、大学の採点環境へのアクセスが保証されるわけではありません。
| 公開資料 | 読む内容 | ここで作る独自の成果物 |
|---|---|---|
| アーカイブのIntro 1~3、CS168教科書のレイヤー、ヘッダー、設計 | 多重化とベストエフォート配送 | 各ヘッダーと、それを解釈するコンポーネントにラベルを付ける |
| Project 1ガイドとProject 1Aの手順 | TTL制限付きUDPプローブと引用パケット | 演習A: 応答を送信台帳と照合する |
| Project 1Bの手順 | 不完全、無関係、重複した応答 | ホップを作り上げず、誤解を招く証拠を棄却する |
| アーカイブのRouting 1~7、Project 2の手順 | ルーティング状態とフォワーディング動作の違い | ルーティングポリシーと収束に進む |
| アーカイブのTransport 1~4、Project 3の手順 | シーケンス空間、受信ウィンドウ、再送、タイマー | 演習B: ストリーム配送、フレーミング、輻輳を分ける |
| アーカイブのDNS、HTTP/CDN、エンドツーエンドTLSに関する資料 | 名前解決、セキュリティ、アプリケーションの境界 | 演習C: 境界ごとに必要な証拠を選ぶ |
CS168 Project 3で実装するTCPは、輻輳制御を含まない部分実装です。 輻輳に関する講義は別に読んでください。トランスポート課題に合格しても、本番用輻輳制御が実装されている証拠にはなりません。 アーカイブのセットアップ情報にはPython 3.7のテストに関する記載と、学期が異なるディレクトリ名が混在しています。 任意課題を選ぶ場合は課題固有のセットアップに従い、ダウンロードした正確なリビジョンを記録してください。このワークブックのゲストで使うPythonをダウングレードしてはいけません。 教科書はベータ版を名乗っています。実装の詳細はプロトコル仕様で確認してください。
任意の発展課題として、バイトストリーム、所有権、ビルドツール、デバッグについて理解した後にC++のCS144へ進む方法があります。 歴史的なcs144.github.ioのトップページは、今回の確認時には閲覧できませんでした。報告された404は有効なラボ前提ではありません。 学期を選ぶ前に、Stanfordの公式講座一覧と現在の手順を再確認してください。 実際に入手できるスターターリポジトリ、ライセンス、コンパイラー、テストを記録します。 このワークブックは、現在利用可能な無償リポジトリ/採点環境や履修方法を保証しません。 完了条件にCS144は含まれず、採点対象となる実装コードも転載していません。
ツールの準備と証拠の要件
初級編のゲストツールに戻ってください。コマンドが使えることは前提ではなく、開始条件です。 使い捨てゲスト内に限り、そのページにあるパッケージ選択の事前確認/インストール手順を使ってください。 Rockyで既存のcurl-minimalが動作する場合は、そのプロバイダーを維持してください。
| このワークブックでの役割 | Ubuntuのパッケージ/プロバイダー | Rockyのパッケージ/プロバイダー | ここで必要か |
|---|---|---|---|
| HTTPクライアントとバージョン表示 | 既存のcurl | 既存のcurl-minimalまたはcurl | 必須 |
| 上限付きサーバーと分析 | python3、バージョン3.9以降 | python3、バージョン3.9以降 | 必須 |
| ソケット/アドレスの観測 | iproute2 | iproute | 必須 |
| キャプチャとオフライン解析 | tcpdump | tcpdump | 実測パケットの証拠に必要 |
| 実行時間の上限とハッシュ計算 | coreutils | coreutils | 必須 |
| 将来行う任意の経路プローブ | traceroute。初級編のtracepathは別のツール | traceroute。tracepathはiputilsに含まれる | 不要。演習Aはオフライン |
| 任意のDNS調査 | bind9-dnsutils | bind-utils | 不要。実際のDNS問い合わせは要求しない |
リポジトリをチェックアウトしたゲストで、次を実行します。
command -v python3 curl ip ss timeout sha256sum tcpdump
python3 --version
curl --version
ip -Version
ss -V
tcpdump --version
sha256sum examples/networking/foundations/http_lab.pyゲストのリリース、カーネル、リポジトリのリビジョン、ヘルパーのハッシュ、ツールのバージョン、curlの機能一覧を記録してください。 curlにHTTP/2/HTTP/3機能がない場合、それはクライアントの機能上の制限であり、サーバーの障害ではありません。 開始前にss -ltn 'sport = :18080'を確認してください。何らかのリスナーがある場合は中止し、全箇所で別の未使用ポートを選んでください。 無関係なリスナーを終了させてはいけません。
試行ごとにmkdir -m 700 protocol-evidence-01で専用の証拠ディレクトリを作成します。すでに存在する場合は別の名前を選んでください。 以下の例ではリポジトリのルートからこの名前を使います。 キャプチャにはレッスンの合成コンテンツだけを含めます。認証情報、Cookie、実際のユーザートラフィックは不要です。 各項目をmeasured、imported、synthetic、design-onlyのいずれかとして分類し、時刻、観測者、名前空間、キャプチャフィルターを記録します。 提供された記録は、自分のゲストで測定した結果ではありません。
各演習で使う概念
| 境界 | 不変条件/区別 | それだけでは不十分な証拠 |
|---|---|---|
| IP → トランスポート | Protocol/Next Headerが次のパーサーを選ぶ | ポート443だけではHTTPSやQUICを立証できない |
| プローブ → ICMPエラー | エラーにはトリガーとなったパケットが引用される | 外側のルーターアドレスだけではプローブを特定できない |
| TCP → アプリケーション | TCPは順序付けられたバイトストリームを届ける | send()/recv()の境界はHTTPメッセージの境界ではない |
| 受信側 → 送信側 | 広告された受信ウィンドウが受信側の負荷を制御する | 受信バッファーの割り当て量は輻輳ウィンドウではない |
| ネットワーク → 送信側 | 輻輳制御が経路上の負荷を制御する | 再送が1回あっても輻輳の場所は分からない |
| アプリケーション → ユーザー | HTTPステータス/本文がアプリケーションの結果を示す | TCP接続の確立は要求した操作の成功を意味しない |
ストリームの意味とシーケンス空間についてはTCP RFC 9293を参照してください。 ウィンドウを使った説明では、送信中データを考慮したうえで、有効な送信量はcwndと受信ウィンドウの両方に依存します。 ペーシング、送信可能なアプリケーションデータ、実装の詳細も送信量を制約します。 純粋なACKはシーケンス空間を消費しませんが、SYNとFINはそれぞれ1つの位置を消費します。
演習A: プローブ照合台帳
目的: 不完全な経路観測を説明し、無関係な応答をホップとして扱わない。 環境: 紙またはローカルエディターを使います。パケットは送信せず、ルーターも作成しません。 CS168のtracerouteガイドを読んでから、ICMP RFC 792を確認してください。 既存のルーティング/ICMPガイドで、ICMP Echoプローブ方式を確認します。これはCS168のUDP方式とは異なります。
次の独自の合成送信台帳を作成します。以下のアドレスは文書用であり、プローブ先ではありません。
run,probe,ttl,src,dst,protocol,sport,dport
paper-01,A,1,192.0.2.10,198.51.100.20,UDP,41000,33451
paper-01,B,2,192.0.2.10,198.51.100.20,UDP,41000,33452
paper-01,C,3,192.0.2.10,198.51.100.20,UDP,41000,33453次のデコード済み記録はpcapでも、測定した時刻でもありません。
| 記録(受信順) | 外側の応答 | 引用された元のパケット | 判定 |
|---|---|---|---|
| R1 | 192.0.2.1、ICMP 11/0 | AのIPv4ヘッダー+UDPヘッダー全体 | 記入する |
| R2 | 192.0.2.1、ICMP 11/0 | R1と同一の引用内容 | 記入する |
| R3 | 203.0.113.7、ICMP 11/0 | Bのタプル。ただし宛先は198.51.100.99 | 記入する |
| R4 | 198.51.100.20、ICMP 3/3 | CのIPv4ヘッダー+UDPヘッダー全体 | 記入する |
| R5 | 203.0.113.8、ICMP 11/0 | UDPポートより前で終わるIPv4ヘッダーの引用 | 記入する |
record、candidate_probe、decision、reason、confidence、missing_fieldsを含む台帳を作成してください。 matched、duplicate、unrelated、insufficient evidenceをそれぞれ別の判定として使います。 図をつなげるために、Bへの応答を作り上げないでください。
次に、独自のケースを3つ追加します。
- ポートが再利用されたため、以前の実行から遅れて届いた応答。
- 長さが20 byteを超える、オプション付きの有効なIPv4ヘッダー。
- 宣言した観測期限を過ぎてから届いた応答。
それぞれについて、曖昧さを解消する識別子と送受信ウィンドウを述べ、手元の引用情報だけでは判定できない状況も説明してください。 ICMP引用部にアプリケーションnonceが含まれるとは限りません。取得できないbyteを使う設計にしないでください。 ICMP Echoプローブの場合は、存在しないUDPポートを考え出さず、引用されたidentifier/sequenceを照合してください。
予想される観測結果: AではTTL=1の応答を1つ説明できる。Cでは相関するPort Unreachableが、このUDPプローブの宛先到達を示す。 否定的な観測結果: R2は新しいプローブ結果ではない。R3ではBを満たせない。R5ではタプルを一意に特定できない。 Bに一致する応答がない場合、後続のホップから応答が届いていても、収集時間内では不明です。 Bのルーターが転送対象のアプリケーショントラフィックを破棄している証拠にはなりません。 tracerouteのRTTには、応答経路とルーターの応答動作が含まれます。 プローブのポートを変えるとECMPの選択が変わる場合があります。応答したアドレスの一覧だけでは、安定したアプリケーション経路を証明できません。 復元: 元の記録は変更せず保存します。やり直す場合は、派生させた一時台帳だけを破棄します。 完了条件: 各判定で引用フィールドまたは不足フィールドを具体的に示し、追加した3ケースには明示的な棄却/不確実性のルールがあること。
演習B: 1つのTCPストリームにおけるHTTP境界
目的: アプリケーションの長さ、TCPのbyte数、観測されたセグメントが異なる問いに答えることを示す。 環境: 所有するゲスト1台。クライアント/サーバーは127.0.0.1:18080を使い、外部の宛先やプロキシは使いません。 sudoが必要なのはキャプチャだけです。サーバーとクライアントは一般ユーザーで実行します。 以下の要求だけを1件ずつ実行し、要求数は合計10回以内、リクエスト本文は4096 byte以下にしてください。
ターミナルAで、リポジトリのルートから既存のヘルパーを起動します。
python3 examples/networking/foundations/http_lab.py --port 18080 --duration 180リスナーが現れたら、ターミナルBでもリポジトリのルートからキャプチャを開始します。
sudo timeout --signal=INT --kill-after=2s 20s \
tcpdump -i lo -p -nn -U -s 512 -c 120 -w - \
'tcp port 18080' > protocol-evidence-01/http.pcap \
2> protocol-evidence-01/capture.logターミナルCから要求を送る前に、ログにキャプチャの「listening on」行が表示されるまで待ちます。 シェルが自分のユーザーとして出力ファイルを作成し、tcpdumpは標準出力へpcapバイトを書き出します。 キャプチャは120パケットまたは20秒で停止します。timeoutの終了コード124はタイマー到達を示すだけで、ネットワーク障害の証拠ではありません。 終了ステータスと最後のキャプチャカウンターを保存してください。スナップ長512 byteではペイロードが切り詰められる場合があります。その上限を記録します。
curl --disable --noproxy '*' --max-time 3 --http1.1 -i \
http://127.0.0.1:18080/lesson
curl --disable --noproxy '*' --max-time 3 --http1.1 -I \
http://127.0.0.1:18080/lesson
printf 'phase=one\nphase=two\n' | \
curl --disable --noproxy '*' --max-time 3 --http1.1 -i \
--data-binary @- http://127.0.0.1:18080/echo
curl --disable --noproxy '*' --max-time 3 --http1.1 -i \
http://127.0.0.1:18080/missingechoの入力は、両方のLF文字を含む20 byteです。 各応答はノートに別々に保存し、ステータス、Content-Length、実際のコンテンツを特定してください。 GET /lessonのコンテンツは6 byteです。HEADは同じ表現について説明しますが、本文を返しません。 存在しないパスはHTTP 404を返します。--failを指定しない場合、このHTTPエラーでもcurlが正常終了する場合があります。 HTTP通信には成功していますが、リソース検索には失敗した状態です。
権限を使わずに、完了したキャプチャをデコードします。
tcpdump -nn -tttt -vv -r protocol-evidence-01/http.pcap \
'tcp port 18080'
sha256sum protocol-evidence-01/http.pcapフラグ、シーケンス範囲、キャプチャ破棄についてはtcpdumpのマニュアルを使って説明してください。 2つのエンドポイントの組み合わせから接続を1つ選び、捕捉できていればSYN、SYN-ACK、ACK、ペイロード範囲、接続終了を特定します。 特定のパケット数や、要求ごとにセグメントが必ず1つだけあることを要求しません。ハンドシェイク/終了部分がない場合は、収集上の制限として記録してください。 HTTPの生バイト規則はRFC 9112とcurlのマニュアルで確認してください。
独自のフレーミング演習(オフライン): 2 byteの符号なしbig-endian長さの後に、その長さのペイロードが続くパーサーを設計してください。上限は64 byteです。 合成入力は00 03 63 61 74 00 02 6f 6bです。これは独自プロトコルであり、HTTPではありません。 次の配信分割を追跡します。全byteを一度に受信、1 byteずつ受信、最初の長さbyteの後で分割、本文途中で分割。 配信ごとにバッファー内のbyte数、必要なbyte数、出力されたレコードを記録してください。 本文の途中でEOFになる場合と、長さが65の場合も追加します。無期限待機や無制限の割り当てをせず、上限付きエラーを定義してください。 独自のオフラインパーサーを実装しても構いませんが、状態表とすべてのケースを提示すれば演習を満たします。
独自のウィンドウ演習(オフライン): MSSが1000 byte、cwndが4セグメント、受信ウィンドウが9000 byte、送信中データがすでに3000 byteあると仮定します。 ペーシングを無視し、アプリケーションの送信データは準備済みとして、max(0, min(cwnd × MSS, rwnd) − outstanding)を使って追加の送信可能量を計算してください。 次にrwndだけを3500 byteに変更し、最後に0にした場合も計算します。それぞれでどちらの側が制限しているか示してください。 受信ウィンドウが0でもネットワーク輻輳の証拠にはならない理由と、再送だけでは受信側の枯渇を証明できない理由を説明してください。 これは合成状態のスナップショットであり、TCP送信側の全体シミュレーションや実測性能ではありません。
予想される観測結果: 完全な分割であれば毎回同じ2つの論理レコードが生成され、HTTP echoでは入力20 byteが維持される。 否定的な観測結果: 未完成レコードを完成済みとして報告せず、サイズ超過フレームも受け入れない。 記載された簡略モデルでは、それぞれ追加で1000、500、0 byteを送信できる。負の値は0に丸める。 送信側チェックサムエラーのように見えるものは、オフロード時の観測が原因の場合があります。キャプチャ破棄が自動的に経路上の損失を意味するわけではありません。 復元: 自分のフォアグラウンドヘルパーだけをCtrl+Cで停止するか、180秒のタイマー切れを待ちます。キャプチャにも独自の上限があります。 リスナーが残っていないか再確認します。証拠は保持し、破棄する場合は名前を指定したファイル/ディレクトリだけを削除してください。
演習C: ポート番号ではなく、境界を立証する
目的: 名前解決、トランスポート、セキュリティ、アプリケーションのどの層で失敗したかを区別するために、必要最小限の証拠を計画する。 環境: 入手可能なら既存の所有トレースを使うオフラインレポート。公開サイトへのプローブは不要です。
| ケース | 要求する証拠 | 棄却すべき誤った結論 |
|---|---|---|
| DNSからAレコードが返るが、TCP接続に失敗する | リゾルバーの結果、選択されたアドレス、接続エラー、エンドポイントのキャプチャ | 「DNSが成功したのでサービスも動いている」 |
| AAAAレコードはあるが、ゲストに使用可能なIPv6経路がない | アドレスファミリーごとの経路/アドレス状態とクライアントの選択 | 「IPv6のDNS応答があるのでIPv6で到達できる」 |
| TCP接続は成功するが、TLS証明書の検証に失敗する | 想定するホスト名、信頼/検証エラー、TLSエンドポイントのアイデンティティ | 「復旧を証明するために証明書検証を無効にする」 |
| HTTPS要求がHTTP/1.1でネゴシエートされる | クライアントの機能とネゴシエートしたHTTPバージョン | 「ポート443または--http2がHTTP/2を証明する」 |
| HTTP/2がTCP上で複数のストリームを使う | ストリームIDと接続/トランスポートの損失証拠 | 「多重化するとTCPのヘッドオブラインブロッキングがなくなる」 |
| HTTP/3が使われていると思われる | エンドポイントでのQUIC/バージョンとアプリケーションのネゴシエーション証拠 | 「UDP/443のパケットはすべてHTTP/3だ」 |
HTTP/2 RFC 9113、QUIC RFC 9000、HTTP/3 RFC 9114を読んでください。 HTTP/2はTCP上でアプリケーションストリームを多重化します。TCPのbyteが不足すると、複数ストリームへの配送が遅れる場合があります。 QUICはUDP上でストリーム、信頼性、輻輳制御を提供し、TLSを統合します。HTTP/3はHTTPをQUICに対応付けます。 あるQUICストリームに影響する損失で、別のストリームへの配送が妨げられるとは限りません。ただし、共有される輻輳上限とアプリケーションの依存関係は残ります。 暗号化されたパッシブキャプチャからHTTP本文を取得できるとは限りません。エンドポイントで平文を記録することは別の観測点です。
各ケースについて、関連する境界を図にし、肯定的な主張、否定的な主張、次に行う観測を1つずつ書いてください。 curlの--resolveを使うと、TLSに使うURLのホスト名を維持しながらアドレス解決だけを切り分けられる理由を説明してください。DNSをテストしているとは主張しないでください。 --http3のフォールバック動作と--http3-onlyの違いを区別してください。そのようなテストを計画する前に、ローカル環境でのサポート状況を確認します。 演習BのIPv4専用ヘルパーは、クライアントフラグを変えてもIPv6/TLS/HTTP/2サーバーにはなりません。
IPv6 RFC 8200とICMPv6 RFC 4443を使って、演習Aを紙面上で拡張してください。 TTLをHop Limitに、IPv4のヘッダー長解析をIPv6/拡張ヘッダー解析に、IPv4 ICMPタイプをICMPv6タイプに置き換えます。 IPv6ルーターは転送中のパケットをフラグメント化しません。Packet Too Bigの証拠はTime Exceededとは役割が異なります。 台帳にアドレスファミリーとスコープを含めます。IPv6のNeighbor DiscoveryはARPではありません。
予想される観測結果: レポートで、認証されたアプリケーション応答と、到達性およびクライアント機能を区別する。 否定的な観測結果: サポートされないツールと存在しないトレースは利用不可と記録し、リモートプロトコルの実測失敗とは扱わない。 復元: 実行状態に変更はありません。インポートした元の証拠とその出所を維持してください。
完了とポートフォリオへの引き継ぎ
- [ ] 資料のURL/学期、閲覧日、ゲスト/ツールのバージョン、ヘルパーのリビジョン/ハッシュを記録する。
- [ ] 演習Aの5つの記録と、追加した3ケースを、ホップを作り上げずに説明する。
- [ ] ステータス、コンテンツ長、1つのTCP接続、キャプチャの制約を含むHTTP実測証拠を保存する。
- [ ] フレーミングの分割不変性と、不正/不完全なケースを2つ示す。
- [ ] 受信フロー制御と輻輳制御を説明し、この小さなワークロードではどちらもベンチマークできない理由を述べる。
- [ ] 境界に関する6ケースすべてとIPv6の拡張を完了する。
- [ ] リスナー/キャプチャの停止を確認し、未完了の観測があれば特定する。
- [ ] 棄却した選択肢の理由を添えてクイズに回答する。
キャプチャ権限がない場合でも、オフライン作業を完了し、パケット収集は保留中と記録してください。インポートしたキャプチャは分析に使えますが、新たに再現した実験として提示してはいけません。 このポートフォリオで示すのは観測と障害の推論能力であり、資格証明や、すべてのプロトコルに関する普遍的な専門知識ではありません。
エキスパート編のコース一覧に戻り、ルーティングに進むか、Linux性能でホスト上の証拠をさらに学びます。 この証拠の要件を自動化の総合演習にも適用してください。