追加パッケージなしで利用可能なTCPの疎通確認方法(Linux)

記事タイトルとURLをコピーする

はじめに

こんにちは、〇〇界隈とすぐ言ってしまう人は信用できない界隈の久保です。

AWSに限らず、ネットワークやサーバー・コンテナの構築を行う場合ネットワークの疎通確認が必要なケースがあります。
ただ、様々な理由で対象サーバーにパッケージを追加することができないといったケースもあるかと思います。

本記事ではAmazon EC2でよく利用されるAmazon Linux 2023において、追加のパッケージやソフトウェアの追加インストール不要で利用可能な疎通確認方法をご紹介します。

/dev/tcp

bash限定 とはなりますが、/dev/tcpを利用することでTCPの疎通確認を行うことが可能です。

timeout 3 bash -c "</dev/tcp/[ホスト名またはIP]/[ポート番号]" && echo "OK" || echo "Failed"

実行例

接続成功の場合:

$ timeout 3 bash -c "</dev/tcp/aurora-test-db.cluster-abcdefghijk.ap-northeast-1.rds.amazonaws.com/3306" && echo "OK" || echo "Failed"
OK

接続失敗(タイムアウト)の場合:

$ timeout 3 bash -c "</dev/tcp/x.x.x.x/8888" && echo "OK" || echo "Failed"
Failed

curl

なお、単にTCPの3ウェイハンドシェイクの確認をするだけであれば、デフォルトでインストールされているcurlでも可能です。

なお、Amazon Linux 2023では初期状態ではcurlコマンドでtelnetプロトコルが利用できないため *1 、curlでHTTPやFTP以外の接続確認ができません。
しかし、単にTCPレベルの接続確認であればHTTPでやってしまえます。
ただし、TCPとしてはOKでもHTTPとしては失敗となるため、結果が少しわかりにくくなります。

curl --connect-timeout 3 http://[ホスト名またはIP]:[ポート番号]

実行例

接続成功の場合:
MySQLポート番号での疎通確認の場合、HTTPではないため結果はエラーになりますが以下の出力であればTCPとしては接続できています。

$ curl http://aurora-test-db.cluster-abcdefghijk.ap-northeast-1.rds.amazonaws.com:3306
curl: (1) Received HTTP/0.9 when not allowed

接続失敗(タイムアウト)の場合:

$ curl --connect-timeout 3 http://x.x.x.x:3306
curl: (28) Connection timed out after 3002 milliseconds

接続失敗(ポート拒否)の場合:

$ curl --connect-timeout 3 http://localhost:8888
curl: (7) Failed to connect to localhost port 8888 after 0 ms: Could not connect to server

python

Amazon Linuxに限らず、多くのLinux distributionではpythonが使えると思います。
pythonのsocketモジュールを使うことでも疎通確認が可能です。

python3 -c "import socket,sys; \
host,port=sys.argv[1],int(sys.argv[2]); \
s=socket.socket(); \
s.settimeout(3); \
print('OK' if not s.connect_ex((host,port)) else 'Failed')" \
[ホスト名またはIP] [ポート番号]

実行例

接続成功の場合:

$ python3 -c "import socket,sys; \
host,port=sys.argv[1],int(sys.argv[2]); \
s=socket.socket(); \
s.settimeout(3); \
print('OK' if not s.connect_ex((host,port)) else 'Failed')" \
aurora-test-db.cluster-abcdefghijk.ap-northeast-1.rds.amazonaws.com 3306
OK

接続失敗(タイムアウト)の場合:

$ python3 -c "import socket,sys; \
host,port=sys.argv[1],int(sys.argv[2]); \
s=socket.socket(); \
s.settimeout(3); \
print('OK' if not s.connect_ex((host,port)) else 'Failed')" \
www.serverworks.co.jp 8888
Failed

おわりに

telnetコマンドやtelnetが扱えるcurl、ncコマンドがあるとより簡単なのですが、ないものは仕方ないということでいくつかの方法をご紹介しました。

最後にそれぞれのメリット・デメリットをまとめます。

方法 メリット デメリット
/dev/tcp(bash組み込み) ・追加インストール不要(bash標準機能)
・シンプルなワンライナーで実行可能
timeoutと組み合わせやすい
・bash依存(zshやshでは不可)
・接続成功/失敗の判定しかできない(詳細エラーは分からない)
curl ・標準的に多くの環境にインストール済み
・HTTP経由での疎通確認に便利
・接続成功/失敗がステータスコードやメッセージで分かる
・HTTP(S)前提のため、非HTTPプロトコル(MySQL、Redisなど)には不向き
・成功しても実際のプロトコル確認にはならない
Python(socketモジュール) ・プロトコル非依存で柔軟に利用可能
・成功/失敗だけでなく詳細エラーを制御可能
・スクリプトとして再利用・拡張しやすい
・Python実行環境が必要(軽量な環境では入っていない場合も)
・ワンライナーに比べると準備がやや手間

絶対パッケージ入れたくない界隈の皆様におかれましては、是非一度お試しください。

*1: Amazon Linux 2023でインストール済みなのは "curl-minimal" のため、"telnet://" が利用できません。

久保 賢二(執筆記事の一覧)

猫とAWSが好きです。