📚 Linuxで動かしながら学ぶTCP/IPネットワーク入門
なぜこれを学ぶか
最近キャッチアップしたものが以下になる。
React
TypeScript
-
Rails7.0
これを現役エンジニアの方にお話したとき、OSI参照モデルのアプリケーション層に寄っている(否定されたわけではないです)と言われて、確かに。と思った。
その中で次に学習すると良いかもと候補に出た中にTCP/IP
とLinux
が入っていた。
元々興味があり、書籍は購入したものの進めていなかったので今回学習しようと思った。
書籍
Linuxで動かしながら学ぶTCP/IPネットワーク入門
1. はじめに
本書は、環境構築を少しでも楽にするためにLinux
のNetwork Namespace
という機能を使う。
本書で扱わないこと
- IPv6
- データリンク層のプロトコルのイーサネット以外
- TCP/IPについては網羅的ではない。(理解できるように説明するのみ)
今回の勉強会で扱うこと
0.75h
第1回 - TCP/IP
- TCP/IPを構成する要素
- インターネットが動作する原理
- Network Namespace
- Network Namespaceの使い方
- IPというプロトコルについて
- Network Namespaceを通じて、インターネットが動作する原理について
0.75h
第2回 - イーサネット
- イーサネットがどのような役目を果たしているか
- トランスポート層のプロトコル
- 通信の種類の識別について
- 通信に信頼性を持たせるためのプロトコルについて
- アプリケーション層のプロトコル
- 実用的な通信について
- NAT
- NAT(NetworkAddressTranslation)という仕組み・原理
ここは扱いません
- ソケットプログラミング
- Pythonを使ってTCP/IPを扱うプログラムの記述方法について
5min
2. TCP/IPの復習 TCP/IPとは
TCP/IPは、皆さんが日常的に利用しているインターネットを構成するプロトコルの総称です。プロトコルというのは、異なる複数の参加者同士で、物事を円滑に進めるための「決めごと」です。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.15)
たくさんあるプロトコル
TCP/IPにはたくさんのプロトコルがあります。たとえば「TCP/IP」という言葉自体が、TCPとIPという2つの代表的なプロトコルの名前からきています。それぞれの正式名称は、次のとおりです。
- TCP(TransmissionControlProtocol)
- IP(InternetProtocol)
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (pp.15-16). Kindle 版.
なぜ複数のプロトコルが必要なのか?
TCP/IPに複数のプロトコルがある主な理由は役割分担
IPの役割は目的地まで荷物を運ぶことです。ただし、IPだけでは実際に目的地まで荷物が到着する保証はありません。現実の世界で、運送会社がお客さんの荷物を勝手に捨ててしまえば大事件かもしれません。ですが、インターネットの世界では日常茶飯事に起こっていることです。そのため、荷物が目的地までちゃんと届いたか管理するプロトコルとしてTCPを使います。
※荷物は単なるメタファーで実際にはビット列で表現されたデータです。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.16). Kindle 版.
プロトコルの階層構造
OSI参照モデルとTCP/IP参照モデル
IPであればネットワーク層という階層に対応します。また、TCPはトランスポート層という異なる階層に対応します。つまり、両者は異なる階層、言いかえれば異なる役割を持ったプロトコルということです。なお、階層のことはレイヤー(Layer)と呼ぶこともあります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.18). Kindle 版.
TCP/IPはOSI参照モデルから独立した存在でもある
OSI参照モデルの階層構造でそれぞれどのように扱うか
OSI参照モデルでは、階層構造が低くなるほどより抽象度の低い具象的な概念を扱います。
たとえば、階層構造でもっとも低いところにある物理層で扱うのは、通信に使うビットを電気や光でどう表現するかといったことです。反対に、階層構造における位置が高ければ、より抽象度の高い概念を扱います。たとえば、もっとも高いところにあるアプリケーション層のプロトコルの1つであるHTTPではWebページのコンテンツなどを扱います。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.20). Kindle 版.
プロトコル(決めごと)は誰が決めているか?
IETF(InternetEngineeringTaskForce)という組織が標準化の主体になってる。
IETFという組織が、トップダウンでプロトコルを決めているように聞こえてしまうかもしれません。実際には、RFCを記述したり、その内容について議論しているのは世界中のITエンジニアたちです。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.20). Kindle 版.
10min
2.4 TCP/IPハンズオン ピンポーン、ごめんください
ping
コマンドを使ってみる!!(TCP/IPのネットワークで疎通を確認するので使用される)
目的は、手紙でいえば「ご機嫌いかが」と便りを出して「こちらは元気です」と返事が戻ってくるのを確かめることです。もし、返事が戻ってくれば安心できますし、戻ってこなければ「何かあったのでは」と心配になりますよね。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.24). Kindle 版.
コマンドでは、宛先として8.8.8.8
というIPアドレスを指定します。
$ ping -c 3 8.8.8.8
これをPing(ピン)を打つ
という
ping
コマンドを打ってみる
実際に$ ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=119 time=13.900 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=119 time=8.556 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=119 time=15.529 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 8.556/12.662/15.529/2.978 ms
ping
コマンドの結果を読んでみる
64 bytes from 8.8.8.8: icmp_seq=0 ttl=119 time=13.900 ms
この部分は、8.8.8.8
というIPアドレスを持った通信相手から、応答が3回あったということを示している。
-c 3
は、応答を要求するメッセージを3回送るという意味、後ろにはかかってくるまでにかかった時間も記述があります。
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 8.556/12.662/15.529/2.978 ms
上記は、統計情報で応答が届いた割合や、応答が届くまでにかかった時間に関する統計量が表示される。
「3つ要求を送って、3つ応答が戻ってきました。途中で失われた内容は0%です」
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.27). Kindle 版.
15min
2.5 IPアドレスとは IPアドレスとは、IP(InternetProtocol:インターネットプロトコル)というプロトコルで通信するのに必要な識別子の一種のこと
IPアドレスの特徴
- インターネット上で一意である
- つまり
8.8.8.8
はインターネット上にはGoogleの公開サーバ以外ないことを指す
- つまり
- インターネット上で一意なのは、グローバルアドレスという種類のみ
- 上記とは逆の概念にパブリックアドレスがある(こちらは企業・家庭などで重複することもある)
- インターネット上の住所というメタファーという表現がよくされる
- インターネットでは通信する相手のIPアドレスが必要になる
- IPでは、荷物のことを
パケット(Packet)
、データグラム(Datagram)
と呼ぶ - IPでデータをやりとりする際の単位がパケットになる
- パケットにはヘッダを付属する
上記のようにダイアグラムで示される構造のことをプロトコルのフォーマットという
自分のMACのIPアドレスを確認してみる
$ ip address show
上記のコマンドでたくさんの情報が出でくるが、重要なのはinet
の後の部分がPCのIPアドレスです。
lo0
やen3
などは、ネットワークインターフェイスという
IPアドレスは、必要に応じてネットワークインターフェイスを付与される。
- ネットワークインターフェイス
lo0
には127.0.0.x
というIPアドレスが付与されています - ネットワークインターフェイス
en3
には10.0.2.xx
というIPアドレスが付与されています
上記で127.0.0.x
というIPアドレスは、ループバックアドレスという特殊なIPアドレス です。
ping
コマンドを打つ
ループバックアドレスに$ ping -c 3 127.0.0.x
PING 127.0.0.1 (127.0.0.x): 56 data bytes
64 bytes from 127.0.0.x: icmp_seq=0 ttl=64 time=0.124 ms
64 bytes from 127.0.0.x: icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from 127.0.0.x: icmp_seq=2 ttl=64 time=0.236 ms
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.119/0.160/0.236/0.054 ms
ここで重要なのは、time
の項目です。
応答が戻ってくる時間がすごく短くなっている。
次に...10.41.194.xxx
は、何か?
この環境ではこちらが差出人に相当するIPアドレスとして使われます。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.36). Kindle 版.
10.41.194.xxx
を詳しく見ていく
tcpdump
コマンドを使用する。
$ tcpdump -tn -i any icmp
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
# 別ターミナルで以下を実行する
$ ping -c 3 8.8.8.8
以下のようにターミナルが更新される。
$ tcpdump -tn -i any icmp
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
IP 10.41.194.243 > 8.8.8.8: ICMP echo request, id 41080, seq 0, length 64
IP 8.8.8.8 > 10.41.194.243: ICMP echo reply, id 41080, seq 0, length 64
IP 10.41.194.243 > 8.8.8.8: ICMP echo request, id 41080, seq 1, length 64
IP 8.8.8.8 > 10.41.194.243: ICMP echo reply, id 41080, seq 1, length 64
IP 10.41.194.243 > 8.8.8.8: ICMP echo request, id 41080, seq 2, length 64
IP 8.8.8.8 > 10.41.194.243: ICMP echo reply, id 41080, seq 2, length 64
上記は、それぞれの行に1つのパケットが対応しています。
行の先頭にある"IP"という表記が、これがIPのパケットであることを示しています。その次の列に書かれているのは、送信元と送信先のIPアドレスです。つまり、最初のパケットは送信元が10.0.2.15で、送信先が8.8.8.8ということになります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.39). Kindle 版.
読み進めるとICMP
と書かれています。
これはPing
の通信がIPとICMPの組み合わせで成り立っていることを示している。
pingコマンドはICMPのエコーリクエストとエコーリプライというメッセージをやり取りする、と先ほど述べました。先ほどの表示では、まさにそのやり取りが確認できます。こちらから送っているのはICMPのエコーリクエストで、相手から戻ってきているのがエコーリプライです。また、エコーリプライが戻ってくるときには、パケットの送信元と送信先のIPアドレスが入れかわっています。これはつまり、要求に対する応答となるIPのパケットが、通信相手から送られてきたことを示しています。そして、全体では往復の通信が全部で3回にわたって繰り返されていることがわかります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (pp.39-40). Kindle 版.
5min
2.6 インターネットという壮大なバケツリレー 今までを振り返るとパケットが宛先まで届いたのかわからない
そこで以下のコマンドを使用します。
$ traceroute -n 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 64 hops max, 52 byte packets
1 10.41.128.3 13.771 ms 6.462 ms 20.295 ms
2 103.5.141.249 7.630 ms
103.5.141.251 6.776 ms 6.383 ms
3 172.30.4.49 13.888 ms 12.348 ms 6.346 ms
4 172.30.4.60 6.751 ms 21.856 ms 12.880 ms
5 210.171.224.96 7.609 ms 7.588 ms 8.338 ms
6 108.170.242.193 9.252 ms
108.170.242.129 18.518 ms
108.170.242.161 11.847 ms
7 142.250.224.213 9.747 ms
142.251.60.193 12.698 ms
216.239.43.53 16.323 ms
8 8.8.8.8 12.032 ms 7.185 ms 8.513 ms
「パケットが目的地までに通る道順」とは
パケットが通過したひとつひとつのルータを表しています12。それぞれの行に表示されているIPアドレスは、パケットが通過したルータの持っているIPアドレスです。このとき、パケットが通過するルータの台数は、インターネットにおける論理的な距離のようなものとして扱われます。論理的な距離、つまり通過するルータの台数のことをホップ数といいます。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.48). Kindle 版.
インターネットというのは、たくさんのルータによるパケットのバケツリレーで成り立っている
インターネットはたくさんのルータがパケットをバケツリレーすることで成り立っていることがわかった
traceroute
コマンドの動作原理
traceroute
コマンドは、ネットワークのトラブルシュートによく使われる。
前提
パケットのヘッダには送信元や送信先のIPアドレスの他にさまざまな情報が格納されている。
traceroute
コマンドは、その中でもTLL(Time to Live)というフィールドをうまく使用している。
2.7 次のバケツを誰に渡すか
インターネット上にはたくさんのルータがあるのにどのように解釈しているのか。
TCP/IPの世界では、次にパケットを渡すべき相手をルーティングテーブル(RoutingTable)というもので管理します
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.53). Kindle 版.
ルーティングテーブルを確認してみる
以下はLinuxのルーティングテーブルです。
$ ip route show
default via 100.64.1.1 dev en0
100.64.1.0/24 dev en0 scope link
100.64.1.1/32 dev en0 scope link
100.64.1.32/32 dev en0 scope link
127.0.0.0/8 via 127.0.0.1 dev lo0
127.0.0.1/32 via 127.0.0.1 dev lo0
169.254.0.0/16 dev en0 scope link
224.0.0.0/4 dev en0 scope link
255.255.255.255/32 dev en0 scope link
ルーティングテーブルは、複数のルーティングエントリ16から構成されています。先ほどの表示であれば、それぞれの行がルーティングエントリに対応します。ルーティングエントリを構成する二大要素は、「宛先」と「次にパケットを渡す相手」です。次にパケットを渡す相手のことは、ネクストホップ(NextHop)といいます。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.54). Kindle 版.
以下のようにルーティングエントリの先頭には、宛先となるIPアドレスが記述されている。
default via 100.64.1.1 dev en0
上記を読んでみる。
default
は特殊な宛先を表す。
この宛先は、他のどの宛先にも該当しないときに使われる。(デフォルトルートと言われる)
以下の次に行で宛先になっているものは、複数のIPアドレスをまとめた表現方法です。
100.64.1.0/24 dev en0 scope link
次に宛先の後ろに続くのがネクストホップ(パケットを渡す相手のこと)
宛先がデフォルトルートの場合は、via 100.64.1.1
がネクストホップに該当します。
デフォルトルートのエントリを解釈すると「他に該当しないすべての宛先のパケットは10.0.2.2に転送する」という意味になります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.55). Kindle 版.
先ほどのルーティングテーブルを見るとvia以外にdevとなっているネクストホップもあるようです。これは、該当する宛先についてはそのネットワークインターフェイスを使って通信することを示しています。先ほどの内容を例にすると10.0.2.0/24devenp0s3などが該当します。今回の例では、自分自身がそこに直接つながっているため、ネクストホップとなるルータを介さずに通信できることを意味しています。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.57). Kindle 版.
バケツリレーは、ルーティングという作業である。
- 他のノードからパケットを受け取る
- 受け取ったパケットのヘッダにある送信先IPアドレスを調べる
- ルーティングテーブルから、送信先IPアドレスに一致する宛先を探す
- 一致した宛先に対応するネクストホップを取得する
- 取得したネクストホップにパケットを渡す
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (pp.57-58). Kindle 版.
Start:2min
Close:1min
2章 まとめ 学んだこと
TCP/IPの概要と、インターネットが動く仕組み
具体的には以下のような項目です。
- TCP/IPはたくさんのたくさんのプロトコルで成り立っている
- 上記のプロトコルは役割ごとに階層構造で分類される
- 実際の通信は、役割ごとにプロトコルを選んで、それらを組み合わせて使う
-
ping
コマンドとtcpdump
コマンドを使ってIPというプロトコルの概要を知った- インターネットはIPというプロトコルを使って、パケットという荷物を運んでいる
- 上記で、パケットを目的地まで届ける時に使われる識別子がIPアドレスである
- それぞれのパケットは、IPアドレスがフィールドに書き込まれたヘッダによって表現される
- インターネットでどのようにパケットが目的地まで運ばれるか
- インターネットは、たくさんのルータによるパケットのバケツリレーで成り立っている
- 上記では、ルータはルーティングテーブルという情報をたよりにパケットを渡す相手を決める
- 上記のような通信の様子を
ping
コマンドとtcpdump
コマンドで確かめることができる
5min
3. Network Namespaceの概要 簡単にネットワークが作れて、壊しても誰も文句を言わない環境(Linuxの Network Namespace)
実際にNetwork Namespaceを使ってみる
以下を参考にして環境構築させてもらいました.
以下のip netns add
というサブコマンドを使うことでNetwork Namespaceを作成できる
# sudo ip netns add helloworld
以下のコマンドで作られたNetwork Namespaceを確認する
# ip netns list
helloworld
作ったNetworkNamespaceでは、コマンドを実行できます。この操作には、
ip netns exec
サブコマンドを使います。このコマンドに、NetworkNamespaceの名前と、そこで実行したいコマンドを続けて入力しましょう。すると、指定したNetwokNamespaceの環境を使って、そのコマンドを実行したことになります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.63). Kindle 版.
NetworkNamespaceの環境で# ip address show
サブコマンドを実行します。
# sudo ip netns exec helloworld ip address show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
link/tunnel6 :: brd ::
以下は、前の章の時のip address show
の結果
$ ip address show
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1/8 lo0
inet6 ::1/128
inet6 fe80::1/64 scopeid 0x1
en3: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether ac:de:48:00:11:22
inet6 fe80::aede:48ff:fe00:1122/64 scopeid 0x4
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether a4:83:e7:aa:1e:24
inet6 fe80::14ef:18f3:a972:4a06/64 secured scopeid 0x6
inet 10.27.70.181/20 brd 10.27.79.255 en0
awdl0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether 0a:26:b9:0b:a3:7b
inet6 fe80::826:b9ff:fe0b:a37b/64 scopeid 0xa
llw0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 0a:26:b9:0b:a3:7b
inet6 fe80::826:b9ff:fe0b:a37b/64 scopeid 0xb
NetworkNamespaceを使うと、ネットワーク的にはシステムから独立した領域を作れます。それは、あたかも別にLinuxをインストールしたマシンを用意したかのようです。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.65). Kindle 版.
独立しているのはネットワークインターフェイスだけではなく、ルーティングテーブルも同じです。
以下のコマンドで確認してみる。
# sudo ip netns exec helloworld ip route show
Error: ipv4: FIB table does not exist.
Dump terminated
このエラーは、ルーティングテーブルが存在しないことを示しています。NetworkNamespaceに、ルーティングエントリを何も登録していないためです。つまり、ルーティングテーブルもシステムから独立していることがわかります。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.66). Kindle 版.
15min
Network Namespaceにつないでみよう 初めに作るもの
これから作るのは、次のような構成のネットワークです。白抜きの四角い箱がNetworkNamespaceを表しています。つまり、"ns1"と"ns2"という名前でNetworkNamespaceを作ります。それぞれのNetworkNamespaceは、仮想的なコンピュータが別々にあるようにイメージすると良いでしょう。そして、それらを端点をもった線のようなものがつないでいます。これは、NetworkNamespace同士をつなぐための、いわば仮想的なLANケーブルを表しています。つまり、2台のコンピュータをLANケーブルを使って直結しています。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (pp.67-68). Kindle 版.
Network Namespaceを作る
# sudo ip netns add ns1
# sudo ip netns add ns2
Network Namespace同士を繋ぐ
veth
を作るには、ip link add
サブコマンドを使用します。
以下のコマンドをターミナルで実行します。
# sudo ip link add ns-1-veth0 type veth peer name ns2-veth0
作成したものを確認します。
# ip link show | grep veth
4: ns2-veth0@ns-1-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
5: ns-1-veth0@ns2-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
作成したvethインターフェイスは、2つのネットワークインターフェイスが一対(ペア)になって機能します。これは、片方のネットワークインターフェイスにパケット2が入ると、もう片方から出てくるという特性があるためです。現実世界でいえば、1本のLANケーブルでつながった2枚のネットワークインターフェイスカード(NIC)を想像してください。それを、ソフトウェアで仮想的に作っています。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.70). Kindle 版.
、iplinksetサブコマンドを使うことで、vethインターフェイスをNetworkNamespaceに所属させる
# sudo ip link set ns1-veth0 netns ns1
# sudo ip link set ns2-veth0 netns ns2
設定したいネットワークインターフェイスの名前の後ろにnetnsというキーワードと、NetworkNamespaceの名前を指定します。
momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (p.71). Kindle 版.
vethインターフェイスがNetworkNamespaceで使えるようになった。