TT Lab
はじめる
学ぶ 学習パス コース

ネットワークトラブルシューティング

ソケットとポートの診断

TT Labで続きを見る

目標

リッスンソケットを読み、バインドアドレスがリモート接続に与える影響を自分で再現し、Connection refusedと正常な接続の違いを確認します。

なぜ重要なのか

127.0.0.1:8080でリッスンするプロセスは、同じホストからは完全に動作しますが、外から来る接続はカーネルがRSTで拒否します。つまりrefusedが出ます。そのため、「ローカルでは動くのにリモートだけ動かない」という報告を受けたら、ss -ltnpのLocal Addressの列の1マスを見るだけで、半分は終わります。逆に、そのアドレスが0.0.0.0なのに外からtimeoutなら、そこからファイアウォールとネットワークポリシーを見ます。この切り分けが、調査範囲を半分に減らします。

ステップ

  1. /root/sockディレクトリを作成し、現在リッスン中のTCPソケットの一覧を/root/sock/listen.txtに保存してください。:2222が含まれている必要があります。
  2. 0.0.0.0:8080でリッスンするHTTPサーバーをバックグラウンドで起動してください。採点の時点でも生きている必要があります。
  3. 127.0.0.1:8081でだけリッスンする2つ目のサーバーを起動し、2つのソケットのLocal Address:Portを1行ずつ/root/sock/bind.txtに書いてください。(例: 0.0.0.0:8080と127.0.0.1:8081)
  4. 127.0.0.1:8080に接続できるか確認した結果を/root/sock/nc-open.txtに保存してください。
  5. 誰もリッスンしていない127.0.0.1:9999への接続を試した結果を/root/sock/nc-refused.txtに保存してください。出力にrefusedを意味する文言が含まれている必要があります。
  6. /proc/net/tcpから8080ポートのLISTENソケットの行を探し、そのまま/root/sock/proctcp.txtに保存してください。
  7. 自分のインターフェースのIP(ループバックではないもの)で8080と8081をそれぞれ叩き、結果を/root/sock/scope-test.txtに2行で書いてください。 8080=<open|closed> / 8081=<open|closed>
  8. /root/sock/report.csvを作成してください。1行目はport,bind,protoのヘッダーで、その下に2222、8080、8081の3つのポートについて、それぞれ1行ずつ書いてください。bindは実際のリッスンアドレス、protoはtcpです。

参考

リッスンソケットの確認

/root/sockディレクトリを作成し、現在リッスン中のTCPソケットの一覧を/root/sock/listen.txtに保存してください。:2222が含まれている必要があります。

TCPのリッスンソケットだけを、名前解決なしで、プロセスまで見るオプションの組み合わせです。sshdが2222で動いています。

テストサーバーの起動

0.0.0.0:8080でリッスンするHTTPサーバーをバックグラウンドで起動してください。採点の時点でも生きている必要があります。

python3の組み込みHTTPサーバーをバックグラウンドで起動してください。採点の時点でも生きている必要があるため、nohupやsetsidを併用するほうが安全です。

バインド範囲が異なる2つのサーバー

127.0.0.1:8081でだけリッスンする2つ目のサーバーを起動し、2つのソケットのLocal Address:Portを1行ずつ/root/sock/bind.txtに書いてください。(例: 0.0.0.0:8080と127.0.0.1:8081)

python3 -m http.serverには、バインドアドレスを指定するオプションがあります。2つのサーバーのLocal Addressの列を比べてみてください。

開いているポートの確認

127.0.0.1:8080に接続できるか確認した結果を/root/sock/nc-open.txtに保存してください。

ncの-zは、データを送らず接続だけを試みます。-vを付けると結果の文が出ます。

閉じているポートの確認

誰もリッスンしていない127.0.0.1:9999への接続を試した結果を/root/sock/nc-refused.txtに保存してください。出力にrefusedを意味する文言が含まれている必要があります。

誰もリッスンしていないポートに接続すると、カーネルがRSTを返します。その結果の文言をそのまま保存してください。

/proc/net/tcpを直接読む

/proc/net/tcpから8080ポートのLISTENソケットの行を探し、そのまま/root/sock/proctcp.txtに保存してください。

ポートは16進数で書かれています。8080を16進数にすると何になるでしょうか。状態列の0AはLISTENです。

外側のアドレスから叩いてみる

自分のインターフェースのIP(ループバックではないもの)で8080と8081をそれぞれ叩き、結果を/root/sock/scope-test.txtに2行で書いてください。 8080=<open|closed> / 8081=<open|closed>

ループバックではなく自分のインターフェースのIPで接続してこそ、違いが現れます。2つのポートの結果が異なる必要があります。

リッスンソケットの表を作る

/root/sock/report.csvを作成してください。1行目はport,bind,protoのヘッダーで、その下に2222、8080、8081の3つのポートについて、それぞれ1行ずつ書いてください。bindは実際のリッスンアドレス、protoはtcpです。

CSVはカンマで区切ります。ヘッダー行を含め、先ほど起動した2つのポートがどちらも入っている必要があります。