ソケットとポートの診断
目標
リスニングソケットのバインディング範囲を区別し、ssと/proc/net/tcpの2つの経路で、同じ事実を確認します。
なぜ重要なのか
「サーバーの中でcurlはできるのに、外からはできない」という報告の大半は、ファイアウォールではなく、バインディングの問題です。127.0.0.1:8080にバインドされたソケットは、同じホストから来た接続だけを受け付け、外部のパケットは、カーネルがそもそも渡しません。この区別は、セキュリティ設計でもあります。管理用ポートをわざとループバックだけにバインドするのが、標準的な慣行です。そして、リスニングソケットのSend-Qはバックログの最大値、Recv-Qはacceptの待ちキューの現在の長さです。確立された接続での意味と違うので、よく読み違えられます。
ステップ
/root/netディレクトリで作業します。
python3 -m http.server 8080 --bind 127.0.0.1をバックグラウンドで起動して、PIDを/root/net/http_pid.txtに書いてください。python3 -m http.server 8081 --bind 0.0.0.0をバックグラウンドで起動して、PIDを/root/net/all_pid.txtに書いてください。8080はそのままループバック専用である必要があります。- 2つのポートのバインディング範囲を、
/root/net/binding.txtに、次の2行で書いてください。値はloopbackまたはallです(プレースホルダーは値です)。8080=<값>8081=<값>
- 8081に接続を1つ開いて、閉じずに維持するプロセスを起動し、PIDを
/root/net/client_pid.txtに書いてください。 - 10進数の8080を、16進数4桁の大文字に変えて、
/root/net/hexport.txtに書いてください。 - 8080のリスニングソケットのバックログの最大値を、
/root/net/backlog.txtに、数字だけで書いてください。 - 8080をつかんでいるプロセスのPIDを、
ssで確認して、/root/net/owner.txtに書いてください。 /root/net/portcheck.sh <포트>を作ってください。そのポートで待ち受けていれば、port=<포트> state=listen pid=<PID>を出力して終了コード0、誰も待ち受けていなければ、port=<포트> state=freeを出力して終了コード1です。引数がなければ、0以外のコードです(プレースホルダーは、ポート番号とPIDです)。
参考
ss -ltnHは、ヘッダーなしでリスニングTCPソケットだけを見せます。列の順序は、Recv-Q Send-Q Local Peerです。/proc/net/tcpのlocal_addressは、IP:PORTがすべて16進数で、状態0AがLISTENです。python3 -c "import socket,time; s=socket.create_connection(('127.0.0.1',8081)); time.sleep(9999)" &で、接続をつかんでおけます。- よくある間違い1: ステップ4で、接続を開いてすぐに閉じると、ESTABLISHEDが消えます。
- よくある間違い2: ステップ7で、
-pなしでss -ltnだけを使うと、プロセス情報が出ません。
ループバックだけにバインドしてサーバーを起動する
python3 -m http.server 8080 --bind 127.0.0.1をバックグラウンドで起動して、PIDを/root/net/http_pid.txtに書いてください。
python3 -m http.serverに--bindオプションがあります。バックグラウンドで起動して、PIDを書いてください。
すべてのアドレスにバインドして起動する
python3 -m http.server 8081 --bind 0.0.0.0をバックグラウンドで起動して、PIDを/root/net/all_pid.txtに書いてください。8080はそのままループバック専用である必要があります。
0.0.0.0にバインドすると、どのインターフェースから来ても受け付けます。8080はそのままループバックである必要があります。
バインディング範囲を記録する
2つのポートのバインディング範囲を、/root/net/binding.txtに、次の2行で書いてください。値はloopbackまたはallです(プレースホルダーは値です)。
8080=<값>8081=<값>
ss -ltnのLocal Address列を見てください。2つのポートがどう違うかを書きます。
接続をつかんでおく
8081に接続を1つ開いて、閉じずに維持するプロセスを起動し、PIDを/root/net/client_pid.txtに書いてください。
接続を開いたまま、閉じずに維持する必要があります。python3でcreate_connectionした後にsleepすれば十分です。
/proc/net/tcpを直接読む
10進数の8080を、16進数4桁の大文字に変えて、/root/net/hexport.txtに書いてください。
ポートが16進数で書かれています。8080を16進数4桁の大文字に変えてみてください。
バックログの最大値を読む
8080のリスニングソケットのバックログの最大値を、/root/net/backlog.txtに、数字だけで書いてください。
リスニングソケットでは、Send-Qがバックログの最大値です。ss -ltnの2列目です。
ポートの持ち主を探す
8080をつかんでいるプロセスのPIDを、ssで確認して、/root/net/owner.txtに書いてください。
ssにプロセス情報を見せるオプションがあります。出力から、pid=の部分を取り出してください。
ポート占有の確認スクリプト
/root/net/portcheck.sh <포트>を作ってください。そのポートで待ち受けていれば、port=<포트> state=listen pid=<PID>を出力して終了コード0、誰も待ち受けていなければ、port=<포트> state=freeを出力して終了コード1です。引数がなければ、0以外のコードです(プレースホルダーは、ポート番号とPIDです)。
待ち受けていればpidまで知らせて0、空いていればfreeと1を出します。