ncやtelnetなしにポートの疎通確認をしたい
ポートの疎通確認にはnc(netcat)やtelnetをよく使う。
しかしコンテナや最小構成のサーバではこれらのコマンドが入っていないことがある。
bashには/dev/tcpという仮想ファイルシステムが組み込まれており、外部コマンドなしにTCPの疎通確認ができる。
/dev/tcp の使い方
/dev/tcp/ホスト/ポートに書き込むとTCP接続を試みる。
接続に成功すれば終了コード0、失敗すれば1が返る。
$ (echo >/dev/tcp/8.8.8.8/53) 2>/dev/null && echo "open" || echo "closed"
open
接続できないポートを指定した場合はclosedと表示される。
$ (echo >/dev/tcp/8.8.8.8/9999) 2>/dev/null && echo "open" || echo "closed"
closed
(echo >/dev/tcp/...) のようにサブシェルで囲むのは、接続後にファイルディスクリプタを確実に閉じるため。
タイムアウトを設定する
ポートが閉じていてもファイアウォールでパケットが落とされている場合、接続待ちで長時間ブロックされる。
timeoutコマンドで待機時間の上限を設定する。
$ timeout 3 bash -c "(echo >/dev/tcp/8.8.8.8/53) 2>/dev/null" && echo "open" || echo "closed"
open
timeout 3で3秒以内に接続できなければタイムアウトとして処理される。
ホスト名でも使える
IPアドレスだけでなくホスト名も指定できる。
$ (echo >/dev/tcp/example.com/80) 2>/dev/null && echo "open" || echo "closed"
open
変数で指定する
ホストとポートを変数で渡せる。
HOST=8.8.8.8
PORT=53
(echo >/dev/tcp/$HOST/$PORT) 2>/dev/null && echo "$HOST:$PORT is open" || echo "$HOST:$PORT is closed"
8.8.8.8:53 is open
複数ポートをループでチェックする
HOST=example.com
for PORT in 22 80 443; do
timeout 3 bash -c "(echo >/dev/tcp/$HOST/$PORT) 2>/dev/null" \
&& echo "$HOST:$PORT open" \
|| echo "$HOST:$PORT closed"
done
example.com:22 closed
example.com:80 open
example.com:443 open
注意点
/dev/tcpはbash固有の機能。shやzshでは使えない。
$ sh -c "(echo >/dev/tcp/8.8.8.8/53)"
sh: /dev/tcp/8.8.8.8/53: No such file or directory
スクリプトで使う場合はシバンに#!/bin/bashを指定する。
関連
- ポートを使用しているプロセスの確認は特定ポートの使用状況を確認する(lsof, ss, netstat) を参照
参考
\第一線のプログラマーの行動原理を学べる!/
