Closed10

🐧 Learning TCP/IP networking by exercise on Linux

なぜこれを学ぶか

最近キャッチアップしたものが以下になる。

  • React
  • TypeScript
  • Rails7.0
    これを現役エンジニアの方にお話したとき、OSI参照モデルのアプリケーション層に寄っている(否定されたわけではないです)と言われて、確かに。と思った。
    その中で次に学習すると良いかもと候補に出た中にTCP/IPとLinuxが入っていた。
    元々興味があり、書籍は購入したものの進めていなかったので今回学習しようと思った。

書籍

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

https://www.amazon.co.jp/exec/obidos/ASIN/B085BG8CH5/momijiame-22/

1. はじめに

本書は、環境構築を少しでも楽にするためにLinuxのNetwork Namespaceという機能を使う。

https://github.com/momijiame/linuxtcpipbook/tree/2ndedition

本書で扱わないこと

  • IPv6
  • データリンク層のプロトコルのイーサネット以外
  • TCP/IPについては網羅的ではない。(理解できるように説明するのみ)

今回の勉強会で扱うこと

第1回 0.75h

  • TCP/IP
    • TCP/IPを構成する要素
    • インターネットが動作する原理

https://www.itmanage.co.jp/column/tcp-ip-protocol/
  • Network Namespace
    • Network Namespaceの使い方
    • IPというプロトコルについて
    • Network Namespaceを通じて、インターネットが動作する原理について

第2回 0.75h

  • イーサネット
    • イーサネットがどのような役目を果たしているか
  • トランスポート層のプロトコル
    • 通信の種類の識別について
    • 通信に信頼性を持たせるためのプロトコルについて
  • アプリケーション層のプロトコル
    • 実用的な通信について
  • NAT
    • NAT(NetworkAddressTranslation)という仕組み・原理

ここは扱いません

  • ソケットプログラミング
    • Pythonを使ってTCP/IPを扱うプログラムの記述方法について

2. TCP/IPの復習 5min

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 版.

2.4 TCP/IPハンズオン 10min

ピンポーン、ごめんください

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 版.

2.5 IPアドレスとは 15min

IPアドレスとは、IP(InternetProtocol:インターネットプロトコル)というプロトコルで通信するのに必要な識別子の一種のこと

IPアドレスの特徴

  • インターネット上で一意である
    • つまり8.8.8.8はインターネット上にはGoogleの公開サーバ以外ないことを指す
  • インターネット上で一意なのは、グローバルアドレスという種類のみ
  • 上記とは逆の概念にパブリックアドレスがある(こちらは企業・家庭などで重複することもある)
  • インターネット上の住所というメタファーという表現がよくされる
  • インターネットでは通信する相手のIPアドレスが必要になる
  • IPでは、荷物のことをパケット(Packet)、データグラム(Datagram)と呼ぶ
  • IPでデータをやりとりする際の単位がパケットになる
  • パケットにはヘッダを付属する

上記のようにダイアグラムで示される構造のことをプロトコルのフォーマットという

https://www.itbook.info/study/p87.html

自分の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アドレス です。

https://e-words.jp/w/ループバックアドレス.html

ループバックアドレスに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 版.

2.6 インターネットという壮大なバケツリレー 5min

今までを振り返るとパケットが宛先まで届いたのかわからない
そこで以下のコマンドを使用します。

$ 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 版.

バケツリレーは、ルーティングという作業である。

  1. 他のノードからパケットを受け取る
  2. 受け取ったパケットのヘッダにある送信先IPアドレスを調べる
  3. ルーティングテーブルから、送信先IPアドレスに一致する宛先を探す
  4. 一致した宛先に対応するネクストホップを取得する
  5. 取得したネクストホップにパケットを渡す

momijiame. Learning TCP/IP networking by exercise on Linux (Japanese Edition) (pp.57-58). Kindle 版.

2章 まとめ Start:2min Close:1min

学んだこと

TCP/IPの概要と、インターネットが動く仕組み

具体的には以下のような項目です。

  • TCP/IPはたくさんのたくさんのプロトコルで成り立っている
    • 上記のプロトコルは役割ごとに階層構造で分類される
    • 実際の通信は、役割ごとにプロトコルを選んで、それらを組み合わせて使う
  • pingコマンドとtcpdumpコマンドを使ってIPというプロトコルの概要を知った
    • インターネットはIPというプロトコルを使って、パケットという荷物を運んでいる
    • 上記で、パケットを目的地まで届ける時に使われる識別子がIPアドレスである
    • それぞれのパケットは、IPアドレスがフィールドに書き込まれたヘッダによって表現される
  • インターネットでどのようにパケットが目的地まで運ばれるか
    • インターネットは、たくさんのルータによるパケットのバケツリレーで成り立っている
    • 上記では、ルータはルーティングテーブルという情報をたよりにパケットを渡す相手を決める
    • 上記のような通信の様子をpingコマンドとtcpdumpコマンドで確かめることができる

3. Network Namespaceの概要 5min

簡単にネットワークが作れて、壊しても誰も文句を言わない環境(Linuxの Network Namespace)

実際にNetwork Namespaceを使ってみる

以下を参考にして環境構築させてもらいました.

https://gist.github.com/grgr-dkrk/99d9fb77f592f8a23a8f1cfff0d5afe2

以下の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 版.

Network Namespaceにつないでみよう 15min

初めに作るもの

これから作るのは、次のような構成のネットワークです。白抜きの四角い箱が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で使えるようになった。

このスクラップは10日前にクローズされました
ログインするとコメントできます