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

数年前になるが下記の本を読んだので備忘としてメモを書く。

www.amazon.co.jp

------------

Linuxで動かしながら学ぶ TCP/IP ネットワーク入門

環境構築

TCP/IPとは

  • pingTCP/IPで疎通確認に使われる。例えば、2つのNetwork Namespaceをルータで繋ぎ、一方のNetwork Namespaceからもう一方にパケットを送信できるかを確認できる。

  • tcpdump は通信(例:ping)を覗き見する(=パケットキャプチャ) プログラムである。各パケットの送信元/送信先IPアドレスなどを参照できる

  • traceroute はある通信での経路(Route, 通過した各RouterのIPアドレス) を確認するときに使う

  • ip address showコンピュータのIPアドレスをネットワークインターフェース(NIC無線LANアダプタ) ごとに表示できる。inet という表示の後ろに表示される。

  • ip route show でルーティングテーブル(経路表) を表示できる。**ルーティングテーブルはインターネットに繋がる全てのノード(ホスト含む) がそれぞれ持つ。**先頭列に宛先IPアドレスが表示される。

    インターネットを構成するルータはルーティング(ルーティングテーブルからネクストホップを調べるまでの作業) とフォワーディング(Forwarding, ネクストホップにパケットを渡す作業) を実施している

    ルータはネットワーク層でパケットを転送する機器のこと。

Network Namespace

  • ip nets add ns1 で新たにns1というNetwork Namaspaceを作成することができる。Network Namespaceはネットワーク的にシステムから独立した領域でありルーティングテーブルも独立して持つ。

  • ip link add veth1 type veth peer name veth2 でNetwork Namespace同士をveth(Virtual Ethernet Device, 仮想的なネットワークインターフェース)を使って繋ぐことができる。veth1veth2 は作成するネットワークインターフェースの名前。

    作成したvethはシステムの領域に所属しているためNetwork Namespaceで利用するためにはそこに所属させる必要があり、次を実行する必要がある。

    ip link set veth1 netns ns1

  • IPを使って通信するにはネットワークインターフェース(veth)にIPアドレスを付与する必要がある(ip address add)。

    また、ネットワークインターフェースは初期は無効な状態になっているため有効にする必要がある(ip link set veth1 up)。

  • IPで構築されるネットワークでは異なるセグメント(ネットワークやサブネットワークともいう) 同士で通信したい場合にルータが必要となる。セグメントはIPアドレスのネットワーク部で識別される(同一ネットワークアドレスのIPアドレスは同一セグメントに属する)。

    ルータのネットワークインターフェースに付与するIPアドレスのホストアドレスは自由に設定できるが、一般的にセグメントの先頭または末尾のIPアドレスを使うことが多い。また、下記のアドレスは設定できない。

    • ホスト部のビットが全て1のアドレスはブロードキャストアドレスといいそのセグメントに所属しているノード全てに通信したい場合の宛先に用いる
    • ホスト部のビットが全て0のアドレスはネットワークアドレスとなるためホストアドレスには使えない
  • Network Namespaceにはネットワークインターフェースを複数所属させることができる。例えばルータは1つのNetwork Namespaceとして設定でき、異なるセグメントの橋渡しをするため、各セグメントに所属するネットワークインターフェース (IPアドレス) をそれぞれルータに所属させることになる。

    • Network Namespaceはどの情報で識別可能?ルータのような複数のIPアドレスを保持するものがあるためIPアドレスでも識別不可と思われる。
  • Network Namespace同士で特定のルータを介した通信では、送信元のNetwork Namespaceのルーティングテーブルに、宛先がデフォルトルートのルーティングエントリ(宛先とネクストホップの組) を追加すると良い (ip route add サブコマンド)。

    デフォルトルートはルーティングテーブルの他のどのルーティングエントリの宛先にも該当しない場合の宛先のこと。デフォルトルートを使わずに特定のIPアドレスを宛先としたルーティングエントリを追加しても良いが、この方法だと通信したい相手が増えるたびにルーティングエントリを追加する必要があるため、デフォルトルートで特定のルータを介すようにする。

    送信先のNetwork Namespaceのルーティングテーブルも同様に設定する必要がある(相手からの通信時に必要であるため)。

  • 2つのNetwork Namespace間の通信で、それぞれが異なるセグメントに所属しており、セグメントの間にさらに別のセグメントを介す場合には、間のセグメントとそれぞれのセグメントを橋渡しするルータがそれぞれ必要となる。このような場合は、各ルータは通信したい相手のセグメントとは直接つながっていないため、各Network Namespaceにデフォルトルートとして対応するルータのIPアドレスを追加するのみでは通信できず、各ルータにもルーティングエントリ(宛先は宛先のセグメント、ネクストホップは相手側のルータの自分側のネットワークインターフェースのIPアドレス) を追加する必要がある。つまり、ルータは自身が直接繋がっているセグメント内のIPアドレスであれば自身のルーティングテーブルのネクストホップに設定できる。

  • 上記2つのケースのような人間が人手でルーティングエントリを追加する方式をスタティックルーティングといい、ブロードバンドルータではこちらが使われていることが多いが、ブロードバンドルータでは自動でGUIで設定されるように作られている。

    インターネットはダイナミックルーティング(ルータ同士が自律的に自身の知っているルーティング情報を教え合う方式) で制御されており、BGPという特定のプロトコルが使われている。(特定のネットワークに変更があったからといって全世界のルータを手動で変更するわけにはいかないため)。

イーサネット

  • イーサネット (Ethernet)OSI参照モデルではデータリンク層物理層に対応するプロトコルを含んだ規格のことでありIPを含む上位層のプロトコルのデータを運ぶ。IPのパケットがルータまで辿り着く際にも使われている。

  • IPのヘッダはイーサネットのヘッダの直後に連結され、各ヘッダはIPのパケットとイーサネットのフレーム(Frame, イーサネットでデータを送る単位) を表すため、フレームはIPのパケットという荷物を運ぶトラックと言える。Network Namespace間で通信する際(例:pingを打つ場合) tcpdump コマンドで-e オプションをつけることでイーサネットのヘッダ情報を表示することができる。

  • IPアドレスが分かっている相手と通信するためには、相手のMACアドレス(Media Access Control address, イーサネットのフレームを送受信するネットワーク機器ごとに付与される)を知る必要があるが、MACアドレスは、IPv4ではARP(Address Resolution Protocol)IPアドレスから解決する (IPv6ではICMPv6)。通信した際にARPで既知のIPアドレスを持ったMACアドレスを教えてくれるよう要求をMACアドレスブロードキャストアドレス (特殊なMACアドレス) に投げ、そのIPアドレスを持っている機器が自分のMACアドレスを返答してくれる。

    送信先がブロードキャストアドレスのフレームはフレームが届く範囲の (ブロードキャストドメインという) 全ての機器に対するリクエストとなり、このようなフレームをブロードキャストフレームという。MACアドレスのブロードキャストドメインの範囲はネットワークのセグメントと一般的に同じになる。

    MACアドレスは(ARPで使う際に)ブロードキャストドメインで一意であれば問題にならない。MACアドレスは機器のベンダーごとに割り振られる上位24ビットと、ベンダーが製造する際に割り当てる下位24ビットで構成される。

  • イーサネットを利用した通信でフレームが複数登場する通信は、例えば2つのネットワークセグメント (それぞれの中でNetwork Namespaceを設定) 間でルータを介した通信がある。送信元のNetwork Namespaceからもう一方のNetwork Namespaceに通信を試みたとき、宛先IPアドレスのセグメントが異なっているためルーティングテーブルのデフォルトルートに従いルータのIPアドレスネクストホップとなる。そこでARPを使いデフォルトルートのネクストホップのMACアドレスを解決することになる。

    送信先のセグメントのインターフェースからtcpdumpでその続きを観察することができる。パケットを受け取ったルータは、送信先IPアドレスをルーティングテーブルから調べ、送信先IPアドレスがこのインターフェースのブロードキャストドメインに存在することが分かり、ARPを使って (=ブロードキャストフレームで) 宛先IPアドレスMACアドレスを解決する。

    なお、相手先からの返答時には、必要なIPアドレスMACアドレスの対応関係はARPリクエストを通して知ることができ、その結果はキャッシュされているため、ARPを使う必要はない。

  • 家庭やオフィスでよくあるのがルータに接続するネットワーク機器が複数存在する場合であり、このときブリッジ(データリンク層でフレームを転送する機器、スイッチングハブをより一般化した概念)を使う。ブリッジはMACアドレステーブルで自身のポート (トランスポート層のポートではない) と接続する機器のMACアドレスの対応関係を管理する。

    Linuxのネットワークブリッジという機能を使うことで、3つ以上のNetwork Namespaceを同一のセグメントに接続することが可能になる。ネットワークブリッジのMACアドレステーブルはbridge fdb show サブコマンドなどで確認可能。

トランスポート層プロトコル

  • IPの通信で問題となるのが下記の2点であるが、これを解決するのがトランスポート層TCP(Transmission Control protocol)UDP(User Datagram Protocol)である

    • IPヘッダの情報のみではコンピュータが扱う様々なアプリケーションの通信を識別できない
    • IPパケットは経路上で破棄される恐れがある
  • UDPではポート番号を使ってアプリケーションを識別する。集合住宅をコンピュータのOSとすると、その住所はIPアドレス、各部屋番号がポート番号、各住人がTCP/IPで通信するアプリケーションに相当する。

    なお、他のアプリケーションが使っているポートは別のアプリケーションから利用することは基本的に不可。

    ポート番号は次のように決定される:

    • アプリケーションが通信を待ち受ける立場の場合(例:サーバ・クライアント方式のサーバ)、ポート番号はUDPを使う上位層のプロトコルで決定される (例:DNSならば53番)
    • アプリケーションが通信を自分から始める立場の場合(例:サーバ・クライアント方式のクライアント)、特にアプリ側から指定しない限りOSが自動的にポート番号を選んで割り当てる(Ephemeral Portという)。
  • UDPの通信の様子はncコマンド (正式にはNetcatというプログラム) でサーバ・クライアント方式の通信を確認できる。なお、トランスポート層プロトコルはシステムのループバックアドレスさえあれば観察可能のため、Network Namespaceは必要ない。ダイナミックポート(ポート番号のうち組織が管理していない範囲) を使いサーバ、クライアントを用意しそのポート番号をtcpdumpで観察すると、文字列を送信した際に運ばれる様子が確認できる。

  • UDPコネクションレス型のプロトコルであり、経路上でパケットが破棄されても関与しないが、TCPはコネクション型のプロトコルでありパケットが破棄された場合には再送制御が行われる。また、パケットが送られた順番と到着した順番が変わることがあるが(アウトオブオーダーという)、これが生じた場合にもデータの順序を正しく認識できる。TCPはWebブラウジングで使うHTTPやメールを転送するSMTPで下位層のプロトコルとして使われる。

  • TCPでは通信を始める際にスリーウェイハンドシェイクという方法で通信する。スリーウェイハンドシェイクの中では、コントロールビット (TCPヘッダに含まれるフィールドで6ビット分のフラグから構成される) の中でSYN(Syncronize sequence numbers)とACK(Acknowledgement field significant) というフラグの立ったパケットを送り合う。

    SYNはシーケンス番号を同期し、セグメントが到着する順序やどこまでデータが送信できているか等、データの順番を管理することができる

    ACKはTCPのセグメントを受信した側が立てるフラグでそのセグメントをきちんと受信したことを示す。送信側は、これが返ってこない場合同じセグメントを送信し直す(再送制御)。

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

  • アプリケーション層のプロトコルは無数にあるが、重要なものは3つ:

    HTTP

    • HTTPはサーバ・クライアント方式のプロトコルであり、トランスポート層TCPを用いるテキストベースの (=文字列として解釈できるビット列をやり取りする) プロトコルTCPの80番ポートを使う。
    • HTTPクライアントとしてncコマンドを使い、メソッドと文字列をループバックアドレスに送るとサーバ側でも文字列を確認できる。curlというHTTPクライアントを実装したコマンドでも同様のことができ、URLはncコマンドを使った操作を文字列として表現したものであることが分かる。

    DNS

    DHCP

    • DHCP(Dynamic Host Configuration Protocol) はUDPの67番ポートを使うバイナリベースのプロトコルTCP/IPのネットワークを使う際に必要となる下記のような設定作業を自動で実施する:
      • ネットワークインターフェースにIPアドレスを付与する
      • デフォルトルートのルーティングエントリをルーティングテーブルに追加する
      • 名前解決に利用するネームサーバを指定する
    • 家庭やオフィスのネットワークでは、デフォルトルートとなるサーバがDHCPサーバを兼任することが多く、配布するIPアドレスの範囲やデフォルトルートの情報をDHCPサーバに対し指定しておき、DHCPクライアントはその情報をDHCPサーバから受け取ってネットワークに関する設定作業を実施する。
    • DHCPサーバにはdnsmasq というプログラムの機能を用いる。

NAT

  • NAPT(Network Address Port Translation) (Source NAT, IPマスカレード) を使うと少数のグローバルアドレスを多数のプライベートアドレスで共有でき、IPv4のグローバルアドレスを節約できる。

  • プライベートアドレスは家庭やオフィスといった組織内のネットワークで自由に使えるよう予約されている下記のIPアドレスであり、LANは次からサブネットを切り出して使う:

    • 10.0.0.0/8
    • 172.16.0.0/12
    • 192.168.0.0/16
  • Source NATは一般的にNATやNAPTと呼ばれる場合に指されるもの。IPv4の節約になるのはNAPTの方であり、ルータが送信先がグローバルアドレスで送信元がプライベートアドレスになっているパケットのヘッダで、送信元のプライベートアドレス (厳密にはIPアドレスとポート番号両方) を自身のインターフェースに付与されているグローバルアドレスに書き換えることで、インターネットのホストの台数分だけグローバルアドレスを節約することができる。

    「戻り」の通信の際には、変換を元に戻す反対の処理、つまり、宛先のグローバルアドレス (書き換え後の送信元のグローバルアドレス) をプライベートアドレスに書き換える必要がある。書き換え前後の対応関係をNAPTではセッションと呼んで管理(記憶) しておくことで、インターネットからパケットが戻ってきたときにどのノードにパケットを転送すればよいか判断できる。

  • Destination NATでは「ポートを空ける」、つまり送信先のポートが特定の値になっているTCPUDPのパケットだけを選択的に書き換えてLANに転送することで、つまり特定のポートに関してだけは通信を許可することでインターネットからのパケットをLANに繋がっているノードに転送することができる。インターネットではプライベートIPアドレスを宛先にしたパケットをルーティングできないためである。これによりSourceNATを使う環境でもインターネットを起点とした通信が可能となる。

ソケットプログラミング

  • ソケットはUnix系OSデファクトスタンダードとなっているAPIであり、ネットワークを抽象化したインターフェースである。ホスト間通信やホスト内のIPC(Inter Process Communication) に用いられる。