はじめに
ハッカーの学校という書籍を読んでいて、理論上はIPアドレスだけで通信が可能だがMACアドレスがないと非効率という一文の意味がよく分からなかったので深掘りしてみました!
通信の流れ
そもそも、通信の流れについてふわっと理解していたので、不明な点を調べつつ流れをまとめてみます。
前提として、通信元をクライアントPC、通信先をサーバーPCとします。
- クライアントPCで「https://www.example.com」とブラウザでアクセスする
- OSがDNSサーバーに問い合わせ、通信先であるサーバーPCと繋がっているルーターのグローバルIPアドレスが解決する
- クライアントPCから通信元のクライアントPCと繋がっているルーターに通信が流れる
- この時、送信元のアドレスはプライベートIPアドレス、送信先のアドレスはグローバルIPアドレス
- クライアント側のルーター内で、NAPTを行い、送信元のアドレスがプライベートIPアドレスからグローバルIPアドレスに変換される
- 送信元のグローバルIPアドレスはサーバーPCが返信する時に使われる
- 送信先のグローバルIPアドレス目指して、通信する
- インターネット上の多数のルーター同士が経路情報(ルーティングテーブル)をもとに最適なルートを選び、パケットを中継していく
- 通信先であるサーバーPCと繋がっているルーター内でNAPTを行い、送信先のグローバルIPアドレスからプライベートIPアドレスに変換する
- 通信先であるサーバーPCと繋がっているルーターからARPを使い、送信先のプライベートIPアドレスからMACアドレスを解決
- ルーターがMACアドレスと送信先のプライベートIPアドレスを含んだEthernetフレームを作成
- EthernetフレームとはLAN通信するときの規格
- ルーターからスイッチにEthernetフレームを送信
- スイッチがMACアドレスを確認し、対象のMACアドレスをもつサーバーPCにEthernetフレームを送信する
- サーバーPCのデータリンク層では、自分のMACアドレス宛のEthernetフレームが来たら、上の層に送信する
ポイント
本題である理論上はIPアドレスだけで通信が可能だがMACアドレスがないと非効率という部分に関わってくるポイントは、Ethernetフレームの構造となります。
Ethernetフレームは先頭が宛先のMACアドレスとなりますので、自分の宛先か判断するときに先頭のMACアドレスで判断した方が効率がいいということになります。
ルーターからすると、プライベートIPアドレスで対象のPCがわかるので、プライベートIPアドレスで判定して、対象のPCに通信すればいいのでは?
歴史的理由で、元々MACアドレスで判定する仕組みで、通信に使う規格であるEthernetフレームもMACアドレスで判定する用の構造をしている。
IPアドレスだけで判定する、L3解析というのもあるみたいだが、それをすると処理が遅くなる。
また、IPアドレスだけで判定できるように仕組みや規格を変えるのも現実的ではない
主題とは関係ないが疑問だったこと
同じLAN内で複数のサーバーがある場合、ポートが被るから困らないか?
例えば、プライベートIPアドレスが192.168.0.10でポート番号443というサーバーを公開した場合、サーバーPC側のルーターは、グローバルIPアドレス:443という形で公開する。
なので、サーバーに通信する際、クライアントPCからの通信はグローバルIPアドレス:443という形で、通信先を探す。
この場合、同じLAN内に、192.168.0.10:443, 192.168.0.11:443みたいに二つのサーバーがあった場合、グローバルIPアドレス:443で接続したらどうなるのか?という疑問です。
これはリバースプロキシという仕組みを使うみたいです。
簡単にいうと、リバースプロキシサーバーというものを作成し、グローバルIPアドレス:443にはリバースプロキシサーバーを紐付けます。
こうすると、クライアントPCからのグローバルIPアドレス:443への通信はすべてリバースプロキシサーバーに通信が向かいます。
実際、サーバーを公開する場合は一意なドメインになりますので、クライアントPCからはブラウザでそれぞれ以下のアクセスをすると思います。
- 192.168.0.10:443: www.example.com
- 192.168.0.11:443: api.example.com
通信の情報には、上記のホスト名が付加されているので、リバースプロキシサーバーでは、ホスト名からどのプライベートIPアドレスに通信するか判定します。
LAN内で複数のPCから同じサーバーに通信する場合、通信元の判別はどうする?
クライアントPCから通信する場合、応答先がわかるようにルーター内でプライベートIPアドレスとポート番号をグローバルIPアドレスとポート番号に変換します。
この時、例えば、通信先のポート番号が443の時、こちらのポート番号も443になるのか?LAN内で複数のPCから同じサーバーに通信する時、ポート番号被らないか?と思いました。
調べてみると、クライアントPCから通信する場合、OSが自動的に割り当てる「一時的な」「短命な」ポート番号であるエフェメラルポートを使用して通信するみたいです。この仕組みにより、LAN内で複数のPCから通信しても被らないようです。
おわりに
深掘りしてみると、分からないことや疑問に思うことばかりで興味深かったです。
他にも、階層モデルやもう少し詳細な通信の仕組みについて深掘りたいので、また記事にします。