読書メモ:Linuxで動かしながら学ぶ TCP/IP ネットワーク入門
数年前になるが下記の本を読んだので備忘としてメモを書く。
------------
Linuxで動かしながら学ぶ TCP/IP ネットワーク入門
環境構築
-
下記環境を利用させていただく
TCP/IPとは
-
ping
はTCP/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, 仮想的なネットワークインターフェース)を使って繋ぐことができる。veth1
やveth2
は作成するネットワークインターフェースの名前。作成した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アドレスを使うことが多い。また、下記のアドレスは設定できない。
-
Network Namespaceにはネットワークインターフェースを複数所属させることができる。例えばルータは1つのNetwork Namespaceとして設定でき、異なるセグメントの橋渡しをするため、各セグメントに所属するネットワークインターフェース (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の通信の様子は
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
-
Webブラウジングの際に人間が用いるドメイン名は、DNSを使うことでIPアドレスに解決できる。DNSはUDPの53番ポートを使うバイナリベースのプロトコルである。DNSを使ってドメイン名をIPアドレスに変換することを名前解決という。
-
DNSを使うのはブラウザに限らず、Pingでlocalhostというドメイン名に向けて打つとループバックアドレスに向けて打たれる。
-
ドメイン名の解決はOSのリゾルバというプログラムが担当し、コンピュータ内のhostsというファイルを参照したり外部のサーバ (ネームサーバ) に問合せることで名前解決する。
hostsはテキストファイルにドメイン名と対応するIPアドレスが記載されているが、自分で書き込まない限り最低限しか存在しないため、見つからないときはネームサーバにリゾルバが問合せるが、ネームサーバは加入しているISPが公開しているものや公開DNSサービスがある。
-
コンピュータとネームサーバを中継する機能はDNSのフォワーダやプロキシ、リレーなどと言われ、ブロードバンドルータのIPアドレスがネームサーバのIPアドレスとなっていることがある (ルータのIPアドレスさえ知っておけば良かったりネームサーバの切り替えをルータの設定変更で実施したりできる)。ネームサーバやフォワーダのIPアドレスはOSで管理されている。
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では「ポートを空ける」、つまり送信先のポートが特定の値になっているTCPやUDPのパケットだけを選択的に書き換えてLANに転送することで、つまり特定のポートに関してだけは通信を許可することでインターネットからのパケットをLANに繋がっているノードに転送することができる。インターネットではプライベートIPアドレスを宛先にしたパケットをルーティングできないためである。これによりSourceNATを使う環境でもインターネットを起点とした通信が可能となる。
ソケットプログラミング
- ソケットはUnix系OSでデファクトスタンダードとなっているAPIであり、ネットワークを抽象化したインターフェースである。ホスト間通信やホスト内のIPC(Inter Process Communication) に用いられる。