【読書メモ】Linuxで動かしながら学ぶTCP/IPネットワーク入門

定期的にやってくる「特に勉強したいこともないしネットワークのことでも勉強するか」ってシーズンが来た。ネットワークの考え方とか前よりは分かってきたが、実際のところどういう仕組みなのかピンと来ない。ってことで今回は書籍「Linuxで動かしながら学ぶTCP/IPネットワーク入門」を買って動かしながらやってみたメモ。

書籍については、この著者が書いたはてなブログの記事を参照のこと。

blog.amedama.jp

第一章 はじめに

この本では Network Namespace なる技術を使ってネットワークを構築してゆくらしい。普段から Ubuntu ユーザなので環境構築で特に困りそうなことはない。

第二章 TCP/IP とは

この章ではプロトコルの階層構造とか ping コマンドのような基本的な事項について書かれている。さすがにこのあたりはだいたい知っている。ping は裏で ICMP(Internet Control Message Protocol)プロトコルの echo request/reply が使われているらしい、へー。traceroute コマンドの動作原理についても書かれている。IP ヘッダのフィールドである TTL(Time to Live)がルータを通過するごとにデクリメントされる性質を利用しているらしい。なるほど。ルータはルーティングの情報をルーティングテーブルで管理する。宛先の IP アドレスに応じて via(ネクストホップのルータ)や dev(デバイス)が指定される。ふむふむ。

第三章 Network Namespace

この章では network namespace を使いながらルーティングを設定する。手を動かしながらやってみるとルータを介した ping が動くようになる。ネットワークインターフェイス(veth)ごとに名前や IP アドレスを設定する。network namespace ごとにルーティングテーブルを設定する。

今回の場合は、ルーティングテーブルを設定するときに「宛先がどんな IP アドレスのときにどこに転送する」ことを人間が教えてあげる。ルーティングテーブルは局所的なルールを定義するものだが、それを定義する人はネットワークの全体を把握しないといけない。インターネットを構成するルータではそれが難しいので、動的にルーティングを制御する仕組みとして BGP(Border Gateway Protocol)が存在する。なるほど。

第四章 イーサネット

この章はデータリンク層イーサネットについて書かれている。IP のパケットは複数のフレームを経由して目的の IP アドレスまで運ばれる。イーサネットではフレームを運ぶ先は MAC アドレスによって与えられる。IP アドレスから MAC アドレスは ARP(Address Resolution Protocol)プロトコルを用いて解決される。

前の章の IP のルーティングの話と総合して IP による通信の仕組みを整理してみる。まず、目的地点の IP アドレスが与えられる。ルーティングテーブルを参照することで、目的地点の IP アドレスから次に送信すべき IP アドレスを特定する。そして ARP によって、次に送信する IP アドレスから MAC アドレスを特定する。MAC アドレスが分かったのでイーサネットの仕組みでフレームを送信できる。このように、次の IP アドレスの特定と MAC アドレスの特定を繰り返すことで目的地までバケツリレー的にパケットが運ばれる。

後半は、ブリッジを使うことで複数のネットワーク機器を接続できることが書かれている。network namespace を使う場合はブリッジ用のネットワークスペースを作り、そこに type bridge のネットワークインターフェイスを追加する。それを mater とするリンクを追加してゆけばよい。

第五章 トランスポート層プロトコル

この章ではトランスポート層プロトコルとして UDPTCP を触ってみる。この章に至るまでネットワーク層データリンク層と下ってきたが、ここでトランスポート層まで上る。ネットワーク層までのプロトコルでは、どのパケットがどのアプリケーションのためのものか判別できないという課題があった。これに対してトランスポート層プロトコルでは、パケットにポートの情報を持たせることでどのアプリケーションに向けたものであるかを明示する。

UDP ではポートを指定してパケットを送信できる。これは nc コマンドを使って実験できる。nc コマンドは CTF(capture the flag)をやったときに使ったことがある。サーバ側のポート番号は上位のプロトコルによってだいたい固定で、クライアント側のポート番号はランダムに払い出されることが多い。

TCP では UDP とは違ってパケットの損失の検知や順序を保つことができる。よりリッチな機能を提供するといえる。通信の開始時にスリーウェイハンドシェイクを行う。TCP は信頼性が高いのでより上位の HTTP とか SMTP プロトコルでは前提となっている。

第六章 アプリケーション層のプロトコル

この章ではアプリケーション層の HTTP, DNS, DHCP について書かれている。これまでの章の内容を理解していれば、これらのプロトコルTCP/IP を活用したものであることがよく分かる。

第七章 NAT

この章は NAPT について書かれている。NAPT は、プライベート IP からグローバル IP とトランスポート層のポート番号のペアへ変換する技術である。もちろん一対一対応しているので逆方向に変換もできる。実際にはパケットの書き換えを行っている。NAPT って教科書とかに書いてあるので知識として知っていたが、パケットの書き換えをしているイメージはなかった。言われてみればそりゃそうだ。

前半はソースとなる IP アドレスを書き換える Source NAT について実験できる。今までとの違いは iptables にルールを追加する部分にある。具体的には、対象となる IP アドレスの範囲に対して MASQUERADE(マスカレード)を指定する。「マスカレード」って仮面舞踏会って意味なんだよな。なんとオシャレなネーミング。ちなみに iptables は network space ごとに存在している。

後半は Destination NAT について書かれている。いわゆる「ポートを解放する」ことである。サーバとしてリクエストを受け付けるときにグローバル IP アドレスが埋められたパケットがやってくるので、それをプライベート IP アドレスに変換する処理である。これは iptables で DNAT を指定することで実現される。

第八章 ソケットプログラミング

いよいよ最後の章である。といってもソケットを使ったプログラミングをする話なので、ソフトウェア屋さんである自分にとっては API 叩いてるだけに見える。ただし、ソケットを使ったプログラミングは TCP とか UDP のようなトランスポート層プロトコルに従った通信を実現するものであることは意識したい。HTTP とかのアプリケーション層の話はいったん忘れても問題ない。もし HTTP に代わる天才的なアプリケーション層のプロトコルを思いついたら、この章に書いてあるみたいな感じでソケットプログラミングをやってみよう。他方、TCP でも UDP でもないトランスポート層プロトコルを思いついたら、必ずしもソケットを活用できるわけではない。もっと低レイヤな部分から作ろう。

全体的な所感

一言で言うとめっちゃ良い本であった。分かりやすい。読者に TCP/IP のエッセンスを理解させたいという気合いが感じられた。これまでのネットワークの書籍って独りよがりなものが多いというか、事実を述べるだけになっているものが多い印象がある。ネットワーク屋さんは仕様や仕組みを深く理解してこそ力を発揮できるというのはよく理解できるので、そのあたりについて細かく書かれた書籍が重宝されるのは分かる。ただ、初学者がまず理解すべきなのはプロトコルの階層構造の意義とか、階層構造の概念が現実世界でどのように実装されているのかとか、各レイヤーでどういう情報が加わって何を達成できるようになるのかとかだと思う。この書籍はこういうエッセンシャルな部分を無駄なく教えてくれている。