KLab Expert Camp(第6回:TCP/IPプロトコルスタック自作開発 #4)参加記

先日、KLabさんのKLab Expert Camp(第6回:TCP/IPプロトコルスタック自作開発 #4)(オンライン)に参加させていただきました。 5日間の日程で開催されるこのインターンは2つのコースからなり、講義形式でリファレンス実装に沿ってTCP/IPプロトコルスタックを自作する基本コースと各々が持ち寄ったテーマをメンターの方のもとで開発するアドバンスドコースを選択できます。 私は基本コースに参加したため、基本コースの参加記となります。

基本コースのリファレンス実装であるmicrops1および講義で使用されたスライドはメンターである山本さんが公開されているので、興味がある方は参照してください。

何ができた?

自作のTCP/IPスタックがNetcatと話せるようになりました。 以下の図がNetcatへの接続要求、メッセージ送信と受信、接続終了要求をしている様子です。

今回のインターンで実装したプロトコルスタックは以下のリポジトリにあります。

github.com

日程

5日間を通して順にIP、ICMP、ARPUDPTCPプロトコルのサブセットをボトムアップに実装してきます。 プロトコルの実装だけでなく、プロトコルの管理やユーザランドでハードウェア割込みを模倣するための機構を実装なども行います2。 詳しくはスライドを見てください。

1日目

micropsの全体像の解説から始まり、ネットワークデバイスの管理やループバックデバイスプロトコルがデバイスからデータを受け取る入口となる関数を実装しました。 しばらくはここで作ったループバックデバイスにデータを書き込むことでプロトコルスタックの動作を確認します。

2日目

IPパケットの受け取りと組み立てができるようになり、その上にICMPのサブセットを乗せました3

3日目

EthernetバイスのドライバとARPのサブセットを実装しました。 Ethernetドライバは物理デバイスを相手にするのではなく、TAPデバイスを読み書きすることでLinux側のプロトコルスタックと通信ができるようになっています。 これにより、Linuxプロトコルスタックと自作のプロトコルスタック間でPingが通るようになります。 Linux側のWiresharkでTAPインターフェースをキャプチャすると、自作プロトコルスタックが組み立てたICMPのパケットを受信できていることがわかります。

4日目

IPルーティングのサブセットとUDPを実装しました。 同一ネットワークに無いホスト向けのパケットの場合はルーティングテーブルからデフォルトルートを引き、デフォルトゲートウェイに送る実装を追加することで外部のネットワークと通信できるようになりました4。 ここではGoogle Public DNS(8.8.8.8)にPingを送っています。

また、UDPを実装することでechoサーバ・クライアントを実装でき、Netcatとお話できるようになります。

5日目

TCPのサブセットを実装しました。 UDPと異なりパケットの受け取りや組み立てだけでなく複雑な状態管理や信頼性を担保するための仕組みの実装が必要になります。 実装した機能はコネクションの確立(いわゆる3-Way Handshake)、セグメントの送信、簡単な再送制御、コネクションの切断です。 複雑な再送制御や輻輳制御は読者への課題となっています。

まとめと感想

5日間で、ユーザランドで動作するIP、ICMP、ARPUDPTCPなどの主要なネットワークプロトコルのサブセットを実装しました。 WiresharkやNetcatなどの頻繁に使うツールと徐々に話せるようになっていき非常に楽しかったです。 メンターの山本さんの技術的なサポートも手厚く、気軽に質問できたり、迅速なバグフィックスをしていただいたりととても充実した5日間でした。

加えて、運営のKの27乗さんによるイベント進行がとてもスムーズで、インターン中の5日間は100%プロトコルスタックの実装に集中することができました。 糖分補給用のお菓子や懇親会用のおつまみとお酒が大量に送られてきました。 また、インターン自体は5日間ですが土日を挟んでの開催であり、土日の間に実装を見直したりリフレッシュしたりでき良かったです。

学習用のTCP/IPスタックの実装はほとんど無いため、自作OSにネットワークを乗せたい人や既存のプロトコルスタックのコードを読みたい人の第一歩としてとても魅力的な選択肢になると思います。 興味のある人はぜひ申し込んでみてください。


  1. 正確には、本インターンで実装するプロトコルスタックはmasterではなくkec5ブランチの実装で、インターン用にいくつか機能が削られています。masterにはSocket APIやTUN/TAPだけではなくPF_PACKETを用いたEthernetドライバ実装などがあります。
  2. ユーザランドではパケットが到着した際のハードウェア割込みを捕まえられないので、ハードウェア割込みをシグナルの送受信で模倣します。
  3. ICMPはIPと同じインターネット層のプロトコルですが、実際はIPに包まれて送られます。
  4. Linux側でIPフォワードとアドレス変換の設定をすることでLinuxホストはゲートウェイとなり、[自作プロトコルスタック]<---- (Linuxホスト) ---->[インターネット上のホスト]で通信できるようにします。