ネットワーク●○○○○

ポート番号

Port ・ ぽーとばんごう

1台の機器の中で通信の窓口を区別する番号。IPアドレスが住所ならポートは部屋番号。

✦ 30秒で試す — 航海住所が1つの建物に、Webもメールも取り違えずに届く3枚のタブから同時に443番へつなぐと、どうなる?予想してみる

概要

ポート番号は、1台のコンピュータの中で通信の「窓口」を区別するための番号です。IPアドレスが建物の住所だとすれば、ポート番号は部屋番号にあたります。データが機器まで届いても、その機器の中では Web サーバ、データベース、SSH のサーバなど、いくつものプログラム(プロセス)が同時に動いているかもしれません。届いたデータをどのプログラムに渡すかを決めるのがポート番号の役割です。

開発の現場では「ローカルの3000番でアプリを起動する」「ファイアウォールで443番だけ開ける」「ポートが衝突して起動できない」といった言い回しで日常的に登場します。URL の「localhost:8080」の「8080」もポート番号です。

なぜ生まれたか

IPアドレスだけでは、宛先の「機器」までしか特定できません。しかし1台の機器で動かしたい通信プログラムは1つとは限らず、むしろ複数のサービスを同居させるのが普通です。もし機器単位でしか宛先を指定できなければ、Web とメールを提供するために2台のマシンを用意するか、届いたデータの中身を覗いて振り分ける仕組みをアプリごとに作る必要があります。同じ相手と同時に2本の通信をしたいとき(ブラウザで同じサイトのタブを2枚開くなど)にも、2本を区別する手がかりがありません。

そこで TCP/IP の設計では、IP アドレスの一段内側に16ビットの番号を設けました。1981年の TCP の仕様(RFC 793)や、その前年の UDP の仕様(RFC 768)で、送信元と宛先の両方にポート番号の欄が置かれています。1本の回線・1つのアドレスの上に、多数の独立した通信を重ねて流す(多重化する)ための仕分けの札として、ポート番号は生まれました。

詳細

番号の範囲と割り当て

ポート番号は0〜65535の整数です。0〜1023は「ウェルノウンポート」と呼ばれ、主要なプロトコルに割り当てられています(IANA という組織が一覧を管理しています)。HTTP の80番、HTTPS の443番、SSH の22番、DNS の53番などが代表です。ブラウザで「https://example.com」と打つだけで通じるのは、「https なら443番」という取り決めをブラウザが知っているからです。1024〜49151は「登録済みポート」で、RDBMS の PostgreSQL の5432番や MySQL の3306番などが登録されています。

残りは、クライアント側が一時的に使う「エフェメラルポート」です。IANA は49152〜65535を推奨していますが、実際の範囲は OS によって違い、Windows は49152〜65535、Linux の既定は32768〜60999です。番号の取り決めはあくまで約束事で、どのプログラムがどの番号で待ち受けるかは設定しだいです。PostgreSQL を443番で動かすこともできてしまいます。

通信は5つ組で識別される

見落とされがちですが、ポート番号はサーバ側だけでなくクライアント側にもあります。ブラウザがWebサーバに接続するとき、OS はクライアント側に空いているエフェメラルポート(例: 51234番)を自動で割り当てます。1つの通信は「プロトコル(TCP か UDP か)・送信元IP・送信元ポート・宛先IP・宛先ポート」の5つ組で識別されます。同じPCから同じサーバの443番へタブを何枚開いても混線しないのは、タブごとに送信元ポートが違うからです。

サーバに届いたデータは、OS が宛先ポート番号を見て、その番号で待ち受けているプロセスへ振り分けます(多重化の逆なので「逆多重化」と呼びます)。応答は送信元ポート(例の51234番)宛に返り、クライアント側の OS がそれを見て正しいタブへ届けます。

サーバ(1台・1つのIPアドレス)クライアント送信元 :51234宛先 :443OS宛先ポートで振り分けWebサーバのプロセス:443 で待ち受けSSHサーバのプロセス:22 で待ち受けPostgreSQLのプロセス:5432 で待ち受けパケット443225432応答応答は :51234 宛に届く
1台のサーバの中で、OS が宛先ポート番号を見て、待ち受けているプロセスへ振り分ける

プログラムがこの窓口を使うための道具がソケットです。サーバのプログラムは「このIPアドレスとポート番号で待ち受ける」とOSに申し出ます。これを bind(バインド、結びつける)と言い、その番号の窓口を占有することを意味します。

下の部品で確かめてください。ブラウザのタブを押して接続し、断られたらプロセスをつかんでポートの口に置いて(bind して)ください。同じ口に2つ目を置いたり、タブを増やしたりすると何が起きるかも見えます。

⚡ 体験: 1つの IP アドレスの中で、ポート番号で振り分ける
サーバ 203.0.113.5(1台・IPアドレス1つ)OS宛先ポートを見て振り分け:22:443(誰も待ち受けていない):5432:3000(誰も待ち受けていない)止まっているプロセスブラウザ198.51.100.7 → :443ターミナル198.51.100.7 → :22アプリ198.51.100.7 → :5432:51234タブ(送信元ポート)nginx(Web)sshd(SSH)postgres(DB)node(開発用)いま成立している通信(5つ組)— 1行が1本の通信プロトコル送信元IP : ポート宛先IP : ポート渡した先まだありません

まずブラウザのタブ(443番宛)を押して、サーバへ接続してみてください。いまは 22番と 5432番でだけ、プロセスが待ち受けています。

「ポートを開ける」「ポートが衝突する」

運用でいう「ポートを開ける」は、ファイアウォールがそのポート宛の通信を通すように許可することです。セキュリティの基本は「必要なポートだけ開ける」で、公開 Web サーバなら80番・443番以外は閉じておくのが定石です。攻撃者が最初に行うのも「どのポートが開いているか」の調査(ポートスキャン)で、開いたポートはそのまま攻撃できる入口の一覧になります。データベースの5432番や3306番をインターネットに開けたままにする事故は、今も繰り返し起きています。

「ポートの衝突」は開発中によく出会うエラーです。同じIPアドレス・同じプロトコル・同じポート番号で待ち受けられるプロセスは原則1つなので、3000番で開発サーバを起動したまま別のアプリを3000番で立ち上げると「Address already in use」で失敗します。前のプロセスを止めるか、別の番号を指定するのが対処法で、どのプロセスが使っているかは lsof -i :3000 や ss -ltnp で調べられます。

ポートは TCP と UDP で別の空間

ポート番号は UDP と TCP で独立した空間を持ちます。「TCP の53番」と「UDP の53番」は別の窓口で、DNS のように両方を使うプロトコルもあります。「53番を開ける」と言うときは、どちらのプロトコルなのかまで決めないと、ファイアウォールの設定が半分だけ効かない、ということが起きます。

外から見えるポートと、アプリが聞いているポート

1024未満のポートで待ち受けるには、多くの OS で管理者権限が必要です。そのため実務では、アプリケーションを8080番などの大きな番号で動かし、前段のリバースプロキシやロードバランサが443番で受けて転送する構成が一般的です。コンテナの「ポートマッピング」(-p 8080:80 のように、ホストの8080番をコンテナの80番につなぐ設定)や、家庭のルータの NAT が送信元ポートを書き換えて1つのグローバルIPを多数の端末で共有する仕組みも、同じく「外から見えるポート」と「中で使っているポート」を付け替える技術です。接続がつながらないときは、どの区間でどの番号を使っているかを1つずつ確かめると、原因が見えてきます。

試問

IPアドレスが1つのサーバの中で、OS が宛先のポート番号を見て、その番号で待ち受けている(bind した)プロセスへ接続を渡します。止まっているプロセス(nginx と node はどちらも Web のプログラム)をつかんで番号の口に置くと待ち受けが始まり、ブラウザのタブを押すと 443番へ接続が飛びます。「タブを開く」で最大3枚まで増やせます。

✦ 命題挑戦中

IPアドレスが1つのサーバで、ブラウザの3枚のタブを443番へ同時につなぎ、しかも Web のプログラム nginx と node の両方を待ち受けさせよ

  • 443番で Web のプロセスが待ち受けている
  • ブラウザの3枚のタブが、それぞれ別の通信として 443番につながっている(0/3)
  • nginx と node の両方が、このサーバで同時に待ち受けている
⚡ 体験: 1つの IP アドレスの中で、ポート番号で振り分ける
サーバ 203.0.113.5(1台・IPアドレス1つ)OS宛先ポートを見て振り分け:22:443(誰も待ち受けていない):5432:3000(誰も待ち受けていない)止まっているプロセスブラウザ198.51.100.7 → :443ターミナル198.51.100.7 → :22アプリ198.51.100.7 → :5432:51234タブ(送信元ポート)nginx(Web)sshd(SSH)postgres(DB)node(開発用)いま成立している通信(5つ組)— 1行が1本の通信プロトコル送信元IP : ポート宛先IP : ポート渡した先まだありません

まずブラウザのタブ(443番宛)を押して、サーバへ接続してみてください。いまは 22番と 5432番でだけ、プロセスが待ち受けています。