アプリ開発者のための
TCP/IP ネットワーク入門

Yusuke Shinyama, Mar. 2023

概要: この記事では、アプリ開発者の役に立ちそうな TCP/IPネットワークに関する最低限の知識をまとめた。 あくまで視点は「アプリ開発者」なので、 現在の家庭・企業における一般的なネットワーク環境しか想定していないし、 セキュリティに関しても基本的なことしかカバーしていない。 ネットワーク機器の具体的な設定方法や診断については、より専門的な資料を参照のこと。

目的: この記事を理解すると、 まとめ問題1まとめ問題2 および NATの動きを理解する のような問題に答えることができる。 (逆に、現時点でこれができる人には本記事は不要。)

目次

  1. 使用するツールの準備
  2. インターネットの作り方・概要
  3. データリンク層のしくみ
  4. IP層 (ネットワーク層) のしくみ
  5. TCP層 (トランスポート層) のしくみ
  6. アプリケーション層
  7. 暗号化
  8. セキュリティ

0. 使用するツールの準備

以下のツールをインストールして使うこと:

1. インターネットの作り方・概要

1.1. ネットワーク通信の原理

コンピュータのネットワーク

これを実現するには、2通りの方法がある:

インターネットではパケット通信を使っている。

ウェブ LINE メール 動画配信 11.22.33.44 55.66.77.88 123.45.200.10 20.10.8.5
双方向に流れるパケット

インターネット以外に使われている (いた) ネットワーク規格

1.2. ネットワークの「階層」

ネットワークは構築するのが大変だ。(道路と同じ)

解決策: いくつかの取り替え可能な「部品」から作る。(ソフトウェアと同じ)

あるレイヤーを使っている人は、その下の階層を知らなくてもよい。 (そのため揶揄的に“土管”などと呼ばれる。)

OSIの7階層モデル

OSI はネットワーク規格としては普及しなかったが、 その階層モデルはいまだ説明用によく言及されている。

  1. 物理層
  2. データリンク層
  3. ネットワーク層 (= IP層に相当)
  4. トランスポート層 (= TCP層に相当)
  5. セッション層
  6. プレゼンテーション層
  7. アプリケーション層 (= アプリケーション層に相当)

TCP/IPの4階層モデル

アプリケーション層 TCP層 IP層 データリンク層 ケーブル

インターネットではデータリンク層と物理層を区別していない。 また、アプリケーション層から上は「使う人が勝手に決める」。

注意: インターネットの階層でハードウェアが関連しているのは おもにデータリンク層だけである。それ以上の階層は、 すべてソフトウェア的な「部品」であり、 現在は OS の機能の一部として提供されている。

テレビなどと比較すると、インターネットでは上の要素はどれも可変である。 唯一の規格は送受信の方式だけ。そのため、 インターネットは「自由なネットワークだ」といわれる。

すべての通信では、まずデータ (0/1 の列) をどうにかして 別のコンピュータに送らねばならない。

イーサネット (Ethernet)

無線LAN (WiFi)

海底ケーブル

ひとつ隣のホストは別の国である。

伝書鳩

どうにかして 0と1 さえ送れれば、電気を使わなくてもかまわない: http://www.blug.linux.no/rfc1149/

1.4. IP層 (ネットワーク層)

IP = Internet Protocol

インターネット上のある「地点」は IPアドレス によって表現される。 IPアドレスは物理的な場所とは何の関係もない。

IPアドレスの例

ルータ

IPパケットは、複数台のコンピュータを経由して転送される。 このような中継用のコンピュータを ルータ (router) とよぶ。

1.5. TCP層 (トランスポート層)

TCP = Transmission Control Protocol

TCP 層によって、インターネット上のあるホストから別のホストに 「任意の長さの 0 と 1 の列」を送れるようになる。

1.6. アプリケーション層

最後にアプリケーション層が、送られてきたデータを ユーザにとって意味のある方法で利用する。

最近では、この短所を解決するため、さらにこの上に TLS/SSL層などを導入することもある (HTTPSなど)。

アプリケーション層 TCP層 IP層 データリンク層 ケーブル
ノード aa-bb-cc-dd-ee-ff 11-22-33-44-55-66 a1-b2-c3-d4-e5-f6 6f-5e-4d-3c-b2-1a
イーサネット
演習. MACアドレスを調べる

自分のパソコンについている イーサネット の MAC アドレスを調べよ。 (複数のインターフェイスが接続されている場合、MAC アドレスは複数存在することがある。)

イーサネット を使って別のノードにデータを送るときは、 以下のような順序で 0 と 1 を送ることになっている。 なぜか イーサネット では「パケット」ではなく フレーム (frame) と呼ばれている。

Ethernet フレームの構造

10101010 10101011 送信先MACアドレス
(6バイト)
送信元MACアドレス
(6バイト)
データ長
(2バイト)
実際のデータ
(46〜1500バイト)
CRC
(4バイト)
00000000

一般的に、このような決まりを プロトコル (Protocol, 規約) とよぶ。

演習. Ethernetフレームの中身

以下の Ethernet フレームについて問いに答えよ:

06 e6 76 53 06 c8 04 e6 76 53 06 c8 00 05 11 22 33 44 55 aa bb cc dd
  1. 送信元MACアドレスは何か?
  2. 送信先MACアドレスは何か?
  3. 実際のデータは何バイトか?
  4. そのデータは何か?
  5. CRCの値は何か?
演習. Wireshark を使って Ethernet フレームの詳細を確認する

Wireshark を起動後にパケットキャプチャーを開始し、 各パケットの詳細パネルをクリックして イーサネット の送信元・送信先MACアドレスを確認せよ。

Wireshark

ふつう「ネットワークインターフェイス」といえば、 イーサネット などの物理的な接続口をさすが、最近ではソフトウェアによる 「仮想的な」ネットワークインターフェイスも存在する。

(本物の)インターフェイス 仮想インターフェイス
本物のインターフェイスと仮想インターフェイス
演習. 仮想インターフェイスを確認する

自分の PC についている仮想インターフェイスはあるか? ifconfig コマンドで確認せよ。

$ ifconfig

3. IP層 (ネットワーク層) のしくみ

アプリケーション層 TCP層 IP層 データリンク層 ケーブル

データリンク層の機能を使うと、小口のデータを信頼できる方法で 隣の (直接接続されている) ホストに送信できることがわかった。 データリンク層では基本的にどんなデータを送ってもよいが、 たいていは IPパケット の内容が送られている。 これをバケツリレー式に転送していくのが IP層 (ネットワーク層) の役割である。

10101010 10101011 送信元MACアドレス 送信先MACアドレス データ 長 IPパケット CRC 00000000

IP パケットの構造:

バイト 0 1 2 3
0 バージョン/ヘッダ長 タイプ IPパケット長
4 識別子 フラグ
8 TTL プロトコル番号 チェックサム
12 送信元IPアドレス
16 送信先IPアドレス
20 オプション パディング
24 実際のデータ
演習. IPパケットの中身

以下の緑色部分はイーサネット フレームに含まれる 実際の IPパケットを表したものである。 上の図を参考にして、以下の情報を求めよ:

0000 94 09 37 28 5b d5 00 23 81 1a f2 8d 08 00 45 00
0010 00 34 6b 7f 40 00 80 06 00 00 c0 a8 00 0c c0 a8
0020 01 01 c9 34 00 17 25 d0 1e c0 00 00 00 00 80 02
0030 20 00 82 84 00 00 02 04 05 b4 01 03 03 08 01 01
0040 04 02
  1. 送信元 IPアドレス
  2. 送信先 IPアドレス
  3. IP パケットの大きさ
演習. Wireshark を使って IPパケットの中身を観察する

Wireshark を起動後、パケットキャプチャーを開始し、 フィルタバーに ip と入力せよ。 各パケットをクリックして送信元・送信先のIPアドレスを確認せよ。

3.1. IPアドレス

すべての IPパケットには、送信元・送信先のIPアドレスがついている。 これはふつう 4つの 8ビット数 (0〜255) の組として表記する。

注意: MACアドレスが通常ハードウェアごとに固有なのに対して、 IPアドレスは変化することがある。
演習. 自分のIPアドレスを調べる

自分のパソコンについている IP アドレスを調べよ。 (複数のインターフェイスが存在する場合、 ひとつの PC が複数の IP アドレスを名乗っていることがある。)

演習. ping コマンドを使う

ping コマンドは、与えられた IP アドレスの ホストが起動しているか (IP パケットに応答できるか) 否かを調べるものである。 以下のホストに ping コマンドを実行して、 応答があるかどうかを確認せよ:

$ ping 自分のIPアドレス
$ ping 127.0.0.1
$ ping 192.0.2.1
$ ping 1.1.1.1

IPアドレスはどうやって決まるのか

MACアドレスは通常固定なのに対し、IPアドレスは可変である。 IPアドレスがなければ、そもそも IP層を使って通信できないため、 すべての PC は起動時に IPアドレスを決定する必要がある。 現在、IPアドレスを決める方法はおもに 3通り存在する:

  1. 手動で設定する … OSの設定画面等から。
  2. PPPoE を使ってサーバから取得する … 光ファイバーなどで ISP と 1:1 接続されているときに使う方法。 おもに接続用モデムが IPアドレスを取得するときに使う。
  3. DHCP を使って取得する … 複数の PC がイーサネットに接続されているときに使う方法。 ほとんどの家庭・企業ではこの方法を使っている。

DHCPとは

演習. DHCP で供給された IPアドレスを調べる

家庭用ルータの設定画面にログインし、DHCPアドレスの範囲を調べよ。 そのルータを使っているデバイスの IP アドレスを調べ、 指定する範囲内にあることを確認せよ。

3.2. ルーティング

IPパケットは、ふつう複数のコンピュータを中継して送信される。

(注意: 米国英語の "route" / "router" はどちらかというと 「ラウト」「ラウター」に近い発音だが、ここでは日本語の慣例にならって 「ルート」「ルーティング」と表記する。)

ルータは受けとったパケットをいったんメモリに保管し、 適切な送り先に向けて送信する。

家庭用ルータ

1つの回線 (ISP) からくるパケットを複数台のPCに転送する。 たいていの家庭用ルータには、単なるルーティング機能に加えて、後述する ファイヤウォール、NAT、DHCPサーバ およびウェブサーバなどの機能が搭載されている。

業務用ルータ

複数の基幹回線とつながっており、ISPなどで使われる。 Cisco 8000 など。 10Tbps〜200Tbps の処理能力があり、非常に高価。

ルーティングは難しい

MACアドレスは各機器に固有なのに対して、 IPアドレスは各ホストが「勝手に名乗っているだけ」であり、しかもつねに変化している。 つまりルータは世界のどこにいるかわからないホストに対して、 IPパケットを送らなければならない。 しかも、インターネットの正確な全体像はわからない。

3.3. CIDR 方式

小さな組織 (自宅・会社・学校) で、ネットワークが 階層構造 (ツリー構造) になっているときに使える方法。

各ホストは、ルーティングテーブルと呼ばれる情報を持っている。 ここには以下のようなルールが記載されている:

if 送り先 が ある範囲の IPアドレスならば
    インターフェイス1を使う
else if 送り先 が ある範囲の IPアドレスならば
    インターフェイス2を使う
...
else
    インターフェイスNを使う

ここでいう「ある範囲の IPアドレス」のことを、 サブネットワークまたは サブネット (subnet) という。

末端のホストの場合:

ルータ 192.168.1.1 192.168.1.0 末端のホスト 192.168.1.2 192.168.1.3 192.168.1.4
サブネット 192.168.1.0 に接続されているホスト

末端のホストは、ひとつのサブネットに接続している。 これは次のような方法でIPパケットを転送する:

macOSにおけるTCP/IPの設定

ルータの場合:

ルータ 192.168.1.1 192.168.2.2 192.168.1.0 192.168.2.0 ルータ 10.0.1.2 192.168.2.1
ルータが2つのサブネットを中継する

ルータは 2つ以上のサブネットに接続しており、 少なくとも2つのIPアドレスを持っている。 ルータは次のような方法でIPパケットを転送する:

サブネット・マスクとネットワーク・アドレス

あるIPアドレスが特定の「サブネット」に所属しているかどうかは、 以下のようにして決定する:

  1. そのIPアドレスを 32ビットの 2進数表記にする。
  2. サブネット・マスク (subnet mask あるいは netmask) の 32ビット値と AND をとる。
    (つまり、マスクが 0 になっている部分のビットを無視する)
    残ったアドレスを IPアドレスの ネットワーク・アドレス (network address) と呼ぶ。
  3. 2つの IP アドレスのネットワーク・アドレスが等しければ、 それらは同一のサブネットに所属する。
IP アドレス 11110000 10101000 00000001 00000010 (192.168.1.2)
サブネット・マスク 11111111 11111111 11111111 00000000 (255.255.255.0)
ネットワーク・アドレス 11110000 10101100 00000001 00000000 (192.168.1.0)

通常、サブネット・マスクは IP アドレスと同様に表記する。 しかし、単に 1の個数を「/24」のように表すことも多い。

基本的には、IPアドレスの先頭部分がネットワーク・アドレスである。
演習. ネットワークアドレスを求める

以下の IP アドレスに対するネットワークアドレスを求めよ:

  1. 10.0.1.3/8
  2. 128.122.100.181/16 (255.255.0.0)
  3. 192.168.1.9/24 (255.255.255.0)
  4. 166.84.7.55/30 (255.255.255.252)
演習. ルーティングテーブルの実装

あるルータが以下のIPアドレスをもっている。 これらは2つのサブネットに接続しており、 そのうちのひとつはデフォルト・ゲートウェイである。

デフォルト・ゲートウェイ 10.0.2.1 ルータ 10.0.2.2 192.168.3.1 サブネットA サブネットB

以下のIPパケットが来た場合、ルータはパケットを どのように転送すればよいか?

  1. 送信元: 10.0.3.4 → 送信先: 192.168.3.2
  2. 送信元: 192.168.3.3 → 送信先: 10.0.3.1
  3. 送信元: 192.168.3.3 → 送信先: 10.1.3.1

3.4. 広域レベルのルーティング

ネットワークがさらに複雑な場合、 もはや単純な規則では行き先を決定できない。 このような広域用のルータは、インターネットの「地図」のようなもの (ルーティング情報) を持っている。 これはつねに変化するため、たえず更新されている。 (ちなみに、この情報も TCP/IP ネットワーク自身を使って送られる。)

リンク・ステート方式 (Link state routing)

中規模の組織で利用される。各ルータは、ネットワーク上のホストが どのように接続されているか定期的に調査し、ネットワークの「地図」を作成する。 ここから各ホスト間の最短経路を計算する。

A B C D E F G Z 4 2 8 2 5 7 4 4 4 3 5 5 7
リンク・ステート方式で作成される地図の一例

経路ベクトル方式 (Path vector routing)

さらに大規模なルーティングに使われる方式。 インターネットを各自律システム (Autonomous System, AS) に分け、 AS 間での経路情報を交換する。世界には約5万のASがあり、相互に協力している。

各ASは BGP (Border Gateway Protocol) という手順で 「このネットワークはこっち」という経路情報を交換している。 しかし全インターネットの正確な地図を把握できるわけではなく 「だいたいこっちの方に送れば正しいだろう」程度の情報しかわからない。

大規模なルータに要求される性能

業務用ルータ1台は、通常のパソコン数百台分の性能をもっている。 アドレスの照合のために、TCAMという特別なメモリが使われている。

演習. 広域ルーティングの実際

ニューヨークに存在する、とあるサーバの IP アドレスは 166.84.7.55 である。 traceroute コマンド (Windows の場合は、tracert コマンド) を使って、 ここに行くまでの経路を調べよ。

macOS/Linuxの場合:

$ traceroute 166.84.7.55

Windowsの場合:

C:\> tracert 166.84.7.55

4. TCP層 (トランポート層) のしくみ

演習. まとめ問題1

IP層の機能を使うと、世界の離れた場所にパケットを送ることができる。 しかし…

各ルータはパケット正しく送るよう精一杯努力するが、これは ベストエフォート方式 (がんばったら、結果がダメでも許してもらえる) にすぎない。 そこで、信頼性のない IPパケットをうまく使って、 信頼できる、長い 0/1 の列 を送る仕組みを作る。 これが TCP 層である。

アプリケーション層 TCP層 IP層 データリンク層 ケーブル

TCP層までくると、2つのホストは連続した通信ができるので、 これはもはやパケット交換ではなく、仮想的な1本の線とみなせる。

ホスト ポート ホスト ポート 134 8962 65535 134
TCP層におけるポートと仮想回線

4.1. TCPの詳細

TCP層は IP層を利用している。 つまり IPパケットの中に、さらに TCPパケット (TCPセグメント) を入れる。

Ethernetフレーム IPパケット TCPセグメント アプリケーション データ

TCP セグメントの構造

0 1 2 3
0 送り元ポート 送り先ポート
4 シーケンス番号
8 確認応答(ACK)番号
12 フラグ ウィンドウサイズ
16 チェックサム 緊急ポインタ
20 オプション
24 実際のデータ

シーケンス番号と確認応答番号

TCP では通信はつねに双方向である。 2つのホストは (たとえ送るデータがないときでも) つねに次の情報を相手に送っている:

seq, ack はそれぞれ送った (受けとった) データのバイト数に応じて増加する:

ホストAホストB
[seq=1, ack=1, (10バイト)] →
seq +10
ack +10
ack +5 ← [seq=1, ack=11, (5バイト)]
seq +5
[seq=11, ack=6, (0バイト)] →
seq +0
ack +0
ack +3 ← [seq=6, ack=11, (3バイト)]
seq +3
[seq=11, ack=9, (1バイト)] →
seq +1
ack +1
ack +0 ← [seq=9, ack=12, (0バイト)]
seq +0

送り側は、確認応答が来なかったら、以前に送ったパケットを再送信する。

1 8 13 29 1 8
失われたパケット (13)

TCP SYN パケットとハンドシェイク

TCP 通信は、開始時に特別な処理をおこなう。 この処理を 3ウェイ・ハンドシェイク と呼び、 TCP SYN という目印のついたパケットが使われる。

  1. 送り側が TCP SYN パケットを送る。
  2. 受け側が TCP SYN+ACK パケットを送る。
    注意: ここでいう「ACKパケット」は、 確認応答(ack)番号とは別である。
  3. 送り側が TCP ACK パケットを送る。
  4. 送り側、受け側ともに seq=1, ack=1 で通信を始める。

ハンドシェイクが完了すると、2つのホスト間は仮想回線で結ばれた状態となり (接続状態)、 双方向の通信が可能となる。ひとつの仮想回線では、次のものが決まっている:

4.2. 「クライアント」と「サーバ」

IP層においては、すべてのホストはパケットを送受信するという意味で等価であった。

TCP層の通信では、必ず2種類の役割が存在する:

TCPサーバは、特定のTCPポートに TCP SYN が送られるかどうかを ずっと監視していなければならない。このような状態を 「Listen (待ち受け) 状態」という。

クライアント サーバ 接続する Listen
クライアントからサーバへの「接続」
注意: ここでいう「クライアント」「サーバ」は、あくまで特定の動きをするソフトウェア (プロセス) のことであり、 物理的なクライアントやサーバマシンとは関係ない。 実際、ひとつのPC上にクライアント (プロセス) とサーバ (プロセス) が同時に存在することもある。
演習. クライアントとサーバ

自分のPC上で動いているTCPクライアント、TCPサーバを表示してみよう。

Linuxの場合:

$ netstat -n -a -t -p

macOSの場合:

$ lsof -n -P -iTCP

TCPサーバ側の手順:

  1. 特定のTCPポート (たとえば80番) を Listen状態にする。
  2. TCPクライアントが (そのポートに対して) TCP SYN を送ってくるのを待つ。
  3. TCP SYN が送られてきたらハンドシェイクを開始する。
  4. ハンドシェイクが成功すると、TCP接続が Established (確立された) 状態になる。
  5. 以後、そのクライアントと双方向で通信する。
  6. TCP RST パケットが送られてきたら、通信を終了する。

TCPクライアント側の手順

  1. 通信したいサーバの IPアドレス と TCPポート番号 を選ぶ。
  2. そのサーバの特定のポートに向けて TCP SYN を送り、TCPハンドシェイクをおこなう。
    (宛先の IPアドレス や TCPポート番号が間違っていた場合、 その通信はタイムアウトするか、接続拒否 (Rejected) エラーとなる。)
  3. ハンドシェイクが成功すると、TCP接続が Established (確立された) 状態になる。
  4. 以後、サーバと双方向で通信する。
  5. 通信を終了したい場合は TCP RST パケットを送る。
アプリケーション ネットワーク スタック (OS)

TCP 層の機能は、現代のほとんど OS にデフォルトで搭載されている。 そのためアプリケーション側は「どのポートを listen したいか」 「どのポートに接続したいか」を指定するだけでよい。

演習. TCP 接続を使って通信してみる
  1. まず、サーバ側の PC とクライアント側の PC を用意する (どちらも仮想マシンでよい)。
  2. サーバ側PCで、以下のコマンドを実行する:
    $ nc -l 10000
    
  3. クライアント側PCで、以下のコマンドを実行する:
    $ nc サーバIPアドレス 10000
    
  4. サーバ・クライアント側ともに何らかのテキストを入力し、 相手の端末にそれが送信されていることを確認せよ。

netstatコマンドを実行すると、現在その PC上で Listen/Established状態になっている TCPポート一覧を見ることができる。

演習. TCP 接続の状態を確認する

上の演習 を実行中に、 サーバ・クライアントの両方で別のウィンドウを開き、 以下のコマンドを実行して、現在通信中のポートが表示されていることを確認せよ。

Linuxの場合:

$ netstat -n -t

macOSの場合:

$ lsof -n -P -iTCP
演習. Wireshark を使って TCPハンドシェイクを観察する

Wireshark を起動、パケットキャプチャーを開始し、 フィルタバーに ip.addr == サーバIPアドレス と入力せよ。 その後、 上の演習 をもう一度くりかえし TCP の 3ウェイハンドシェイクが行われていることを確認せよ。

4.3. UDP層

TCP層は便利だが、いくつか欠点がある:

これに対して、TCP層のかわりに UDP (User Datagram Protocol) 層というものを使うこともできる。 これはIP層を使っているが、 TCPとは別の方法で通信をおこなう。

アプリケーション層 TCP層 UDP層 IP層 データリンク層 ケーブル

UDPの用途

UDPの欠点

UDPパケットの構造

0 1 2 3
0 送り元ポート 送り先ポート
4 データ長 チェックサム
8 実際のデータ

5. アプリケーション層

TCP/IPのデータリンク層・IP層・TCP層はすべて OS が提供している。 アプリケーション層は、インターネットの機能を実際に活用する部分であり、 ほとんどのアプリ開発者は「アプリケーション層」を作ることになる。

アプリケーション層 TCP層 IP層 データリンク層 ケーブル

実際のアプリケーション層のデータは、Ethernetフレームの中の、 IPパケットの中の、TCPセグメントのさらに中に記録されている。

Ethernetフレーム IPパケット TCPセグメント アプリケーション データ

TCP/IP プログラミング (Socket API)

一般的に、もっともよく使われるのは TCP層の機能である。 現在の OS では「ソケット (socket)」という API が整備されており、 たとえば Python なら、すぐに TCP のサーバ-クライアント間で通信ができる:

server.py (サーバ側):
from socket import *
# TCP用ソケットを準備。
sock = socket(AF_INET, SOCK_STREAM)
# TCPポート 10000番で listen状態にする。
sock.bind(('0.0.0.0', 10000))
sock.listen(1)
# 接続してきたクライアント用のソケットを取得する。
(client, addr) = sock.accept()
# データを受信する。
data = client.recv(10)
print(data)
client.py (クライアント側):
from socket import *
# TCP用ソケットを準備。
sock = socket(AF_INET, SOCK_STREAM)
# ホスト 127.0.0.1 の TCPポート 10000番に接続する。
sock.connect(('127.0.0.1', 10000))
# データを送信する。
sock.send(b'hello')
演習. Python を使った TCPプログラミング

上の 2つの Pythonスクリプト server.pyclient.py を 同一のホスト上で同時に動かし、通信ができていることを確認せよ。

5.1. ドメイン名検索 (DNS)

IP アドレスはそのままでは人間にとって覚えにくい。 そこで DNS (Domain Name System) という仕組みが用意されている。

DNSのしくみ

DNS は TCP/IP の機能を使って作られている。

このようなサーバを用意したあとで、 www.example.com の IPアドレスを求めるには:

  1. ルートサーバ (198.41.0.4) に .com ネームサーバのIPアドレスを問い合わせる → 192.5.6.30
  2. .com ネームサーバに .example.com ネームサーバのIPアドレスを問い合わせる → 199.43.133.54
  3. .example.com ネームサーバに www.example.com のIPアドレスを問い合わせる → 93.184.216.34
  4. 完了。

localhost

127.0.0.1 は 特別な IPアドレスであり、これはつねに「自分自身のホスト」をあらわす。 これをループバックアドレスという。 なお、ホスト名 localhost は つねにループバックアドレスに解決される。

$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.084 ms
...

DNSの欠点

DNS はインターネットの基幹をなすサービスであり、 ほとんどの API やアプリ、サービスなどが DNS に依存している。 DNS が使えなければ、相手の IPアドレスがわからないので、 そもそも通信ができないことが多い。 そのため DNS がうまく動かない場合、 多くのサービスやサイトで大規模な障害が発生する。 これを防ぐため、ネームサーバは多重化されていることが多い。

$ ping www.tabenasugi.com
ping: www.tabenasugi.com: Name or service not known
演習. ホスト名から IP アドレスを求める

host コマンドを使って、 自分がよく知っているホスト名の IPアドレスを求めよ。 (ping でもよい)

$ host ホスト名

5.2. ウェブ (HTTP)

HTTP は、おそらくもっとも有名なアプリケーション層である。

通常、HTTP を使うクライアントを ウェブブラウザ (HTTPクライアント) と呼び、 それに答えるサーバを ウェブサーバ (HTTPサーバ) という。

HTTP のしくみ

  1. クライアントがコンテンツを要求する。(要求、リクエスト)
  2. サーバがコンテンツを提供する。(応答、レスポンス)
  3. 読み込むページ・画像ファイルの数だけ 1., 2. を繰り返す。
クライアント サーバ リクエスト レスポンス
HTTPにおけるリクエストとレスポンス

たとえばブラウザで

http://www.example.com:80/news/
というURL を開くと、 TCPポート 80番に対して接続がおこなわれ、 以下のようなリクエスト文字列が送信される:

GET /news/ HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 6.1;) Gecko/20100101
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,0/0;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
(空行)

これに対してサーバは以下のようなレスポンス文字列を返す:

HTTP/1.1 200 OK
Connection: close
Date: Fri, 20 Feb 2023 08:27:28 GMT
Content-Type: text/html
Content-Length: 9022
(空行)
<html>
...

HTTPリクエスト

HTTP リクエストには GET, POST などいくつかの種類がある。 リクエストはさらに ヘッダ (header) と ボディ (ペイロード) (body, payload) に分かれている。 これらは空行で分けられている。

リクエストヘッダ:
GET /news/ HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/35.0
…
(空行)
リクエストボディ (ペイロード):

ヘッダは 項目名: の形をとる。

ボディは、GETリクエストの場合は空である (つまり何も含まれていない)。

HTTPレスポンス

HTTP レスポンスもまた、 ヘッダ (header) と ボディ (ペイロード) (body, payload) に分かれている。 これらは空行で分けられている。

レスポンスヘッダ:
HTTP/1.1 200 OK
Connection: close
Date: Fri, 20 Feb 2015 08:27:28 GMT
Content-Type: text/html
Content-Length: 9022
…
(空行)
レスポンスボディ (ペイロード):
<html><body>
…

ヘッダは 項目名: の形をとる。

レスポンス内のペイロードには、通常 HTML ファイル (または画像ファイルなど) の内容がそのまま含まれている。 ブラウザはこの内容を解析して表示すると、ページが表示されたことになる。

いろいろな HTTP レスポンス

正常なレスポンスの場合、最初の一行は必ず

HTTP/1.1 200 OK
となっているが、これ以外のレスポンスが返ってくる場合もある。

演習. 人間HTTPクライアント

nc コマンドを使って、 www.example.com サーバに 「人間HTTPクライアント」としてリクエストを送り、 サーバ側のレスポンスを確認せよ。

$ nc www.example.com 80
GET / HTTP/1.0
Host: www.example.com

(サーバからのレスポンス)
HTTP/1.0 200 OK
Content-Type: text/html; charset=UTF-8
Date: Mon, 23 Jan 2023 13:39:22 GMT
…

<!doctype html>
<html>
<head>
…
演習. 人間HTTPサーバ

nc コマンドを使って、 「人間HTTPサーバ」としてブラウザからの リクエストに返答せよ。 まず nc をサーバとして起動し、 ブラウザから http://localhost:8080/ という URLに接続してリクエストが送られるのを確認してから、 応答を入力せよ。

$ nc -l 8080
(クライアントからのリクエスト)
GET / HTTP/1.1
User-Agent: Mozilla/5.0
…

HTTP/1.0 200 OK
Content-Type: text/plain

Hello.

^C
演習. HTTPトラブルシューティング

あるユーザが「インターネットが動かない」といっている。 聞けばブラウザに http://www.example.com/ というアドレスを入力したが、 ページが表示されないのだという。この場合、考えられる原因をすべてあげよ。

  1. どこかのケーブルが断線している
  2. DNS から IPアドレスが解決できていない
  3. ルータが正しく動いていない
  4. パケットが捨てられている
  5. ブラウザにバグがある
  6. 相手のサーバの電源が入っていない
  7. 相手のサーバがListen状態になっていない
  8. 相手のサーバプログラムにバグがある
  9. ...

Webアプリとは

HTTP はあまりにも普及しているため、 こんにち多くのアプリケーションは TCP層を直接使わず、 HTTP「層」を使って構築されるようになっている。 このようなアプリを Webアプリ と呼ぶ。 また、上で紹介した socket API に似た機構を HTTP層の上で実現した WebSocket という仕組みもある。

Webアプリ HTTP層 TCP層 IP層 データリンク層 ケーブル

5.3. 電子メール (SMTP)

HTTP 以外のアプリケーション層の例として、SMTP (Simple Mail Transfer Protocol) がある。 これは特定のサーバ (メールサーバ) の TCP 25番ポートに データを送ると、電子メールを送ることができる。

$ nc gmail-smtp-in.l.google.com 25
220 mx.google.com ESMTP
HELO mail.example.com
250 mx.google.com at your service
MAIL FROM:<送り元メールアドレス>
250 2.1.0 OK
RCPT TO:<xxx@gmail.com>
250 2.1.5 OK
DATA
354  Go ahead zz-1234 - gsmtp
From: <送り元メールアドレス>
To: <xxx@gmail.com>
Message-Id: <zz12345678@mail.example.com>
Subject: test

Hello, this is test!
.
250 2.0.0 OK
QUIT
221 2.0.0 closing connection

6. 暗号化

演習. まとめ問題2

本来、TCP/IP の公式な範疇はTCP層までで、それより上は アプリケーションの責任となっている。しかし TCP 層では 真に安全な通信は実現できない:

最近では、これらの欠点を補うために TCP層の上にさらにもう一段、 (TCP/IPの範疇ではない) 暗号化をおこなう層を追加して使うことが多い。

アプリケーション層 (暗号化層) TCP層 IP層 データリンク層 ケーブル

暗号化通信において特に重要なこと:

暗号化は、必ず通信相手の確認とセットで使わなければ意味がない。

なぜなら悪者も暗号は使えるからだ。 たとえば、中継するホストが正当な相手のフリをして、暗号を使って通信すれば、 結局のところ情報は悪者の手に渡ってしまう (中間者攻撃)。 したがって、暗号はつねに end-to-end で利用する必要がある。

暗号 自分 悪者 (中間者) 本当に通信したい相手
悪者が暗号を使ったら…?

現在普及している暗号化層:

TLS/SSL も SSH も (本来は TCP/IP 層の一部ではなくアプリケーション層なので)、 アプリケーションまたはライブラリの形で提供されている。 どちらもベースになっているのは公開鍵暗号技術である。

公開鍵暗号技術とは

公開鍵暗号技術については、以下のことだけ覚えておけばよい:

演習. 公開鍵を使った認証

Aさんは、自分用の秘密鍵と公開鍵のペアを所持している。 Bさんは Aさんに会ったことはないが、 ネット上でたまたま Aさんの公開鍵を入手した。

Aさん Bさん Cさん 秘密鍵 公開鍵
  1. Bさんが Aさんと実際に通信したとき、 相手が Aさん本人であることをどうやって確認すればよいか?
  2. いっぽう、Aさんのフリをしたがっている偽物 C さんが Bさんと通信したとする。 なぜ Bさんは Aさん本人ではないと見抜けるのか?

6.1. TLS/SSL層

デジタル証明書にはサーバの公開鍵が記載されている。 デジタル証明書は認証局が正当性を保証するもので、 これもまた公開鍵暗号技術を使っている。 詳細は 「デジタル証明書とは何か?」を参照。

認証局 (CA) ブラウザ www.google.com 証明書 Google: 署名: Google
鍵マークが表示されるしくみ

実際の TLS/SSL による通信は openssl コマンドを使って おこなう (なお、HTTPS では通常 TCP 443番ポートが使われる):

$ openssl s_client -connect www.example.com:443
CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Internet\C2\A0Corporation\C2\A0for\C2\A0Assigned\C2\A0Names\C2\A0and\C2\A0Numbers, CN = www.example.org
verify return:1
...

TLS/SSL層は以下のような手順で動作する:

  1. 相手のサーバに TCP接続する。
  2. 暗号化通信を開始する。
  3. サーバからデジタル証明書 (公開鍵) を受けとり、それが正しい相手であることを確認する (TLS/SSLハンドシェイク)。

以上が完了すると、TLS/SSL層は通常の TCP層と同じようにふるまう。 HTTPS の処理は、TLS/SSL層を使う部分以外は HTTP と同じである。

演習. openssl コマンドを使って HTTPリクエストを送る

上で示した openssl コマンドを使って、 先の演習にならい サーバに HTTPリクエストを送り、応答を確認せよ。

$ openssl s_client -connect www.example.com:443
(サーバ証明書の表示)
...
GET / HTTP/1.0
Host: www.example.com

(サーバからのレスポンス)
HTTP/1.0 200 OK
Content-Type: text/html; charset=UTF-8
…

curlコマンド

curl コマンドを使うと、指定した URL に HTTP/HTTPS リクエストを送り、レスポンスを画面に表示する。 nc コマンドや openssl コマンドを使って手で直接 HTTP リクエストを入力するよりも、 こちらのほうが便利。 Webサーバの挙動を調べるのにおすすめ。

$ curl https://www.example.com/
<!doctype html>
<html>
<head>
...

-i オプションをつけると、HTTP のレスポンスヘッダも表示する。

$ curl -i https://www.example.com/
HTTP/2 200
accept-ranges: bytes
age: 49533
cache-control: max-age=604800
...

-H オプションを使えば、リクエストヘッダに任意の値を指定できる:

$ curl -i -H "If-Modified-Since: Sun, 1 Jan 2023 00:00:00 GMT" https://www.example.com/
HTTP/2 304
...
演習. curl コマンドを使って HTTPリクエストを送る

上で示した curl コマンドの使用例を実際に実行せよ。

TLS/SSL 層の欠点

TLS/SSL 層の大きな欠点は、コストがかかることである。 TLS を使うには、ルート認証局を頂点とする、中央集権化された、 全世界規模の 公開鍵基盤 (PKI) を構築する必要がある。 これには大きな手間がかかるうえに、認証局が信頼できない場合がある というリスクも抱えている (参考: 2011年デジノター事件)。

証明書 ルート認証局A 中間認証局B 中間認証局C www.example.com ... ... ...
公開鍵基盤

6.2. SSH層

これに対して、SSH はもっと簡単な仕組みを使って暗号化された通信を実現している:

  1. ユーザは、あらかじめ接続しようとするサーバの公開鍵を、なんらかの方法によって知っておく。
  2. 初回接続時に、サーバは自分の公開鍵の指紋を提示し、その秘密鍵の持ち主であることを証明する。
  3. ユーザがそれを認めれば、暗号化された通信が確立する。
ユーザ サーバ 公開鍵 秘密鍵
公開鍵によるサーバ認証

SSH はもともと Unixマシンの遠隔操作のために開発されたため、 暗号化通信に加えて、ユーザの認証処理もおこなう。 現在、SSH はサーバ管理などでアプリ開発者がよく利用するツールとなっている。

注意: SSH ではユーザの認証にも公開鍵を使っているため、 2種類の「公開鍵」が存在する:

  1. ユーザは、あらかじめ接続しようとするサーバ上の ~/.ssh/authorized_keys ファイルに、自分の認証用の公開鍵を登録しておく。
  2. ユーザはログイン時に、自分がその公開鍵の持ち主であることを証明する。
  3. サーバがそれを認めれば、ログインが許可される。
ユーザ サーバ 秘密鍵 公開鍵
公開鍵によるユーザ認証

SSH の使い方

ここでは典型的な例 (Unixサーバに SSH を使ってログインする) をあげる:

  1. サーバ側で、SSHサーバを起動する。SSHサーバは初回起動時、自動的にそのサーバの公開鍵を生成する。
  2. クライアントPC上で ssh-keygen コマンドを使って、 あらかじめ認証用の秘密鍵・公開鍵ペアを生成しておく。 (これは最初の一度だけ実行すればよい。)
    注意: 既存の鍵ファイルがある場合、ssh-keygen は勝手に上書きしてしまうので注意。
    client$ ssh-keygen -t ed25519
    Generating public/private ed25519 key pair.
    Enter file in which to save the key (/home/euske/.ssh/id_ed25519):
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/euske/.ssh/id_ed25519  (秘密鍵ファイル)
    Your public key has been saved in /home/euske/.ssh/id_ed25519.pub  (公開鍵ファイル)
    ...
    
  3. 秘密鍵ファイルは危険なので、普通は暗号化して記録される。また、そのマシンの外には持ち出さない。
    (複数のマシンで SSH を使う場合、マシンごとに異なる秘密鍵を生成する)
    注意: ssh-keygen で入力するパスフレーズは秘密鍵の暗号化に使うものであって、サーバのログインに使うパスワードとは関連がない
  4. いっぽう公開鍵ファイルは誰に見せてもよいので、ログイン先のSSHサーバ上アカウントの ~/.ssh/authorized_keys にコピーしておく。
  5. SSHサーバ公開鍵の指紋 (fingerprint) を覚えておく。
    たとえば、server.example.com の公開鍵の指紋は SHA256:HLfnjG5dDqVPIfWtG6sNGG5JyY5AYtkxaupGsJffyYs であるとしよう。
  6. クライアントPC上で ssh コマンドを使ってサーバに接続する。
    SSH では、通常 TCP 22番ポートが使われる。
    初回接続時には、サーバ公開鍵の指紋が表示され、確認が要求される。
    client$ ssh user@server.example.com
    The authenticity of host '[server.example.com]:22 ([192.168.1.10]:22)' can't be established.
    ED25519 key fingerprint is SHA256:HLfnjG5dDqVPIfWtG6sNGG5JyY5AYtkxaupGsJffyYs.
    This key is not known by any other names.
    Are you sure you want to continue connecting (yes/no/[fingerprint])?
    
  7. ユーザがこれに yes と答えれば接続が続行する。
    この後、暗号化された秘密鍵を使うためのパスフレーズを入力する。

SSH のよくある使い方はサーバ上のシェルを遠隔実行するためのものだが、 SSH 層自体がいくつかのレイヤーから構成されており、 シェル以外の用途にも利用可能である:

SSH の設定ファイル

ssh コマンドは、自分のホームディレクトリ下にある ~/.ssh/config という設定ファイルを利用する。

たとえば、以下のような内容:

~/.ssh/config
Host myhost
        Port 222                            (TCPポート番号)
        User aws-user-1                     (ログインするユーザ名)
        IdentityFile ~/.ssh/id_ed25519_aws  (認証に使う秘密鍵)
        Hostname myhost.something.us-east-1.servers.aws.com  (実際のホスト名)

を書いておくと、以下のコマンド

client$ ssh myhost

を入力しただけで、 自動的に対象のホスト名・ユーザ・秘密鍵ファイルなどが指定される。

同様のことをコマンドラインで指定すると以下のようになる:

client$ ssh -p 222 -f ~/.ssh/id_ed25519_aws aws-user-1@myhost.something.us-east-1.servers.aws.com

SSH の秘密鍵保持エージェント (ssh-agent)

SSHで認証に使う秘密鍵は、通常は暗号化されており、解凍するには毎回パスフレーズの入力が必要である。 秘密鍵保持エージェントを使うと、一度解凍した秘密鍵を一定時間保持しておくことができるため、 毎回パスフレーズを入力する必要がなくなる。

現在のほとんどのOSでは、秘密鍵保持エージェントは自動的に起動されている。 ここに秘密鍵を追加・削除するには、ssh-add コマンドを使う。

7. セキュリティ

一般に、ネットワークにおける「セキュリティ」とは、以下の性質をさす:

  1. 機密性 (情報が不正に閲覧されない)
  2. 完全性 (情報が不正に改竄されない)
  3. 可用性 (情報へのアクセスが妨害されない)

先に述べた暗号化は上の性質 a., b. に対してある程度は有効だが、 完全ではない (そもそも「完全な」セキュリティなど現実にありえない)。 インターネットは本質的に信頼できないため、 暗号化以外にもネットワークからの攻撃を防ぐ仕組みがいくつも存在する。

7.1. プライベートIPアドレス

そこで、以下のアドレスは組織内で勝手に使ってよいという 決まりになっている。これを プライベート IPアドレス といい、 プライベート IPアドレスを使ったネットワークを プライベート ネットワーク (private network) という。

注意: プライベートIPアドレスのホストは、 インターネット (その組織の外) からは到達できない。

これに対して、世界中から実際に到達可能な「普通の」IPアドレスのことを グローバル IPアドレスという。

166.84.7.55 192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.1 192.168.1.2 192.168.1.4 グローバルIP プライベート ネットワーク プライベート ネットワーク
プライベートIPアドレス と プライベートネットワーク

IPv6

アドレスの不足を解決するため、現在の IP 層を変更して 128ビットのアドレスを使えるようにしたものが IPv6 である。 (これに対して、従来の IP層は IPv4 という。) IPv6 を使えばすべての機器がグローバル IP アドレスを持つことができる。 しかし IPv6 は従来の IPv4 とは互換性がないため、 世界じゅうのルータを入れ換えなければならない。 このため、まだあまり普及していない。

7.2. NAT

具体的には、ルータが「どのプライベートIPアドレスがどのグローバルIPアドレスと 通信しているか」を覚えておき、それに該当する (双方向の) IPパケットが来るたびにそのアドレスを書き換えることによって実現する:

192.168.1.2 192.168.1.1 11.22.33.44 166.84.7.55 Src: 192.168.1.2 Dst: 166.84.7.55 Src: 11.22.33.44 Dst: 166.84.7.55 Src: 166.84.7.55 Dst: 11.22.33.44 Src: 166.84.7.55 Dst: 192.168.1.2
NATによるIPアドレスの書き換え

現在、ほとんどの家庭用ルータ・業務用ルータには NAT 機能が搭載されている。

演習. NATの動きを理解する

プライベートネットワーク内のホスト 10.10.1.2 が ゲートウェイ 10.10.1.1 を経由して、 インターネット上のホスト 55.66.77.88 と通信するとする。 このとき送信されるIPパケットの送信元・送信先アドレスを書け。

10.10.1.2 10.10.1.1 11.22.33.44 55.66.77.88 Src: Dst: Src: Dst: Src: Dst: Src: Dst:

7.3. ファイヤウォール

ファイヤウォール (Firewall) とは、ホストにとって 害のありそうなパケットを無視する (フィルタする) 機器またはソフトウェアのことである。 現在の一般的な環境では:

  1. ルータの機能の一部として
  2. OSの機能の一部として (Windows ファイヤウォール)
提供されている。

基本的にファイヤウォールは「外 → 内」のパケットをフィルタするが、 「内 → 外」のパケットをフィルタすることもある。

パケットをフィルタする

ファイヤウォールには、一般的に以下のようなルールが設定できる:

WAF と IDS/IPS

最近のネットワークでは、ファイヤウォールに加えて 以下のような機器も使われることが多い:

ウェブサーバ WAF IDS/IPS ファイヤウォール インターネット
WAF・IDS・IPS

7.4. プロキシサーバ

プロキシサーバ (proxy server) は、 プライベートネットワーク内にある PC が外部と通信するための方法のひとつである。 NAT とは異なり、IP層 (レイヤー3) ではなく TCP層 (レイヤー4) の接続を制御する。

192.168.1.1:8080 166.84.7.55:80 192.168.1.2 192.168.1.1 166.84.7.55
プロキシサーバ
  1. あらかじめ、プライベートネットワーク内のブラウザが 特定のプロキシサーバに接続するよう設定しておく。
  2. ブラウザがインターネット上のホストにじかに接続するかわりに、 プロキシサーバの指定されたTCPポートに接続し、リクエストを送信する。
    例: ブラウザが http://www.example.com/ にアクセスする場合:
    GET / HTTP/1.1
    Host: www.example.com
  3. プロキシサーバは、リクエスト中の Host: を参照し、 あらためて宛先のWebサーバに向けてTCP接続して、同じリクエストを送る。
    例: 同じリクエストを www.example.com に向けて送る:
    GET / HTTP/1.1
    Host: www.example.com
    …
    

7.5. VPN

プライベートネットワークは、本来は外部からアクセスできない (ファイヤウォールで守られた) 安全な伝送路のみを使って構築するのが普通である。 しかし暗号化を使うことにより、安全でない伝送路を通って プライベートネットワークを構築することが可能になる。 これを VPN (Virtual Private Network、仮想プライベートネットワーク) とよぶ。

VPN では、別々の場所にある2つのサーバ間を暗号化通信でつなぎ、 仮想インターフェイスを使って 見かけ上2つのホストがあたかも同一ネットワーク上に配線されているかのように 通信する。

以下の図は、2つのサブネットを VPN 接続した例を表したものである。 赤い点線は、VPN による (見かけ上の) パケット通信を示している。

ルータ ルータ 192.168.1.2 192.168.1.3 192.168.1.4 192.168.2.100 暗号化 VPN サーバ VPN サーバ
VPNにより2つのネットワークを接続した図

各ホストのルーティング規則は変更されており、 左側のホスト (192.168.1.0/24) と 右側のホスト (192.168.2.0/24) は それぞれ VPN サーバをルータとして経由し、もう片方のホストにパケットを送信する。 また、双方のホスト名が解決できるように、DNSの設定も変更されることが多い。

実際に VPN を実現する手法にはさまざまなものがある:

アプリケーション層 TCP層 IP層 TLS層 TCP層 IP層 データリンク層 ケーブル データ リンク層
VPNの実現手法 (OpenVPN)
アプリケーション層 TCP層 IP層 IPSec層 データリンク層 ケーブル
VPNの実現手法 (L2TP)

7.6. SSHによるトンネリング

一般に VPN を自分で構築・設定するのはかなり手間がかかる。 いっぽう SSH のポート転送機能を使うと、異なるネットワーク間における サーバの共有が簡単にできる。

ローカル→リモート転送

ローカル→リモート転送を使うと、ローカル (クライアント側ネットワーク) から、 リモート (サーバ側ネットワーク) のサーバに TCP接続できる。

以下の構成は、リモートにあるサーバの TCP 80番にアクセスする例である。 この場合、クライアントPC上の SSHコマンド自身がプロキシサーバとして動作し、 8080番ポートに接続された TCP の通信をすべて相手サーバの 80番に転送する。

ルータ ルータ 192.168.1.2 10.0.1.2 暗号化 SSH クライアント SSH サーバ 8080 80
ローカル→リモート転送 (-L 8080:10.0.1.2:80)
演習. ssh コマンドを使ってローカル→リモート転送
  1. リモートのサーバ上で、以下のようにして簡単なサーバプロセスを起動する:
    server$ nc -l 10000
    
  2. クライアントPC上で、「ローカル→リモート転送」を有効にしてサーバにログインする。
    client$ ssh -L 10000:localhost:10000 server.example.com
    
  3. クライアントPC上で、自分自身の TCP 10000番ポートに接続し、 サーバ上のプロセスに接続できていることを確認する。
    client$ nc localhost 10000
    

リモート→ローカル転送

いっぽうリモート→ローカル転送を使うと、リモート (サーバ側ネットワーク) から ローカル (クライアント側ネットワーク) のサーバに TCP接続できる。

以下の構成は、ローカル内のサーバの TCP 80番にリモートからアクセスさせる例である。 この場合、リモートの SSHサーバがプロキシサーバとしても動作し、 ローカルの SSHクライアントと提携して、 8080番ポートに接続された TCP の通信をすべてローカルの 特定ホストの 80番に転送する。

ルータ ルータ 192.168.1.2 10.0.1.2 暗号化 SSH クライアント SSH サーバ 80 8080
リモート→ローカル転送 (-R 8080:192.168.1.2:80)
演習. ssh コマンドを使ってリモート→ローカル転送
  1. クライアントPC上で、以下のようにして簡単なサーバプロセスを起動する:
    client$ nc -l 10000
    
  2. クライアントPC上で、「リモート→ローカル転送」を有効にしてサーバにログインする。
    client$ ssh -R 10000:localhost:10000 server.example.com
    
  3. サーバ上で、自分自身の TCP 10000番ポートに接続し、 クライアントPCのプロセスに接続できていることを確認する。
    server$ nc localhost 10000
    

Yusuke Shinyama