#対象とする読者
- nmapなどでport scanを試してみたはいいがいまいち実感がわかないっていう人
#この記事を読むのに必要な知識
- pythonの基礎知識
- pythonのsocketモジュールの使い方
- ネットワークの基礎知識(必要に応じてわかんないとこを調べれば十分です。)
#この記事でやること
- python3でシンプルなポートスキャナを作成してみること
#警告!!!!
絶対に他人のサーバーに対してポートスキャンをしてはなりません。このページのコードを実行して発生したいかなるトラブルにも責任は取りません。
#で、ポートスキャナとは何ぞや
インターネットでよく使われるプロトコルであるTCPやUDPは、ポートと呼ばれる仮想的な郵便ポストのようなものを使用しています。これによって、一つのPCで様々な通信を同時に行えるというわけです。このポートが開いているか(郵便ポストが手紙を投函できる状態か)を調べるのがポートスキャンです。
#シンプルなポートスキャナを作ってみよう
実際に簡単なポートスキャナを作ってみます。
import socket
max_port = 6000
min_port = 1
target_host = input("Input target host name or address: ")
for port in range(min_port, max_port):
#target_host のポート番号portに接続を試行
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return_code = sock.connect_ex((target_host, port))
sock.close()
#socket.connect_ex は成功すると0を返す
if return_code == 0:
print("Port %d open!" % (port))
print("Complete!")
警告:必ず自分の管理するサーバor仮想マシンに対して実行してください。
注意:環境によっては実行にえらい時間がかかるので、必要に応じてmax_portをいじってください。あくまでポートスキャナについて理解するためのものなので悪しからず。
###解説
- このコードを実行するとtarget_hostのmin_portからmax_portまでのポートに順に接続を試行して、接続が成功すれば(connect_ex()が成功すれば)そのポート番号を出力します。
- このコードの実用上の問題点については補足で述べます。
#まとめ
- 通常のポートスキャンでは普通に接続を試みることでポートが開いているか判断している。
#補足
上のサンプルコードの実用上の問題点は大きく分けて二つです。
実行に時間がかかる
このポートスキャナは1つ接続を試みてレスポンスを待ってそれから次のポート番号を試すので、非常に遅いです。localhostに向けて打つなら問題になりませんが、別のマシンに打つとすごい時間がかかります。この問題を解決には、マルチスレッド方式が一般的で、pythonでは、threadingモジュールを使います。詳しくはほかの素晴らしい解説サイトに譲りますので興味があればどうぞ。
エラーハンドラが全くない
socketモジュールのconnect_ex()メソッドはgaierror(ホストネームが解決不可の時発生)などを処理せずそのまま発生させます。なのでこれのエラーハンドラはあったほうがいいです。また、ポートスキャナは実行時間が長くなりがちなので、 KeyboardInterruptへのエラーハンドラも実装しておくと便利かもしれません。要は以下のようなコードを加えます。
import sys
#中略
try:
for port in range(min_port, max_port):
#中略
except KeyboardInterrupt:
print("KeyboardInterruput.")
except gaierror:
print("Error! host name or address is invalid.")
#以下略