シェルで簡易ポートスキャンツール


制約

nmapもexpectも使えないとする。

実行形式

portscan.sh 接続先リストファイル

リストファイルのフォーマット

IPアドレスorホスト名 ポート番号
.
.
.

区切り文字はスペースかタブとする。空行、コメント行(#)を認める。

出力形式

yyyy/mm/dd HH:MM:SS - yyyy/mm/dd HH:MM:SS IPアドレスorホスト名 ポート番号 OK
yyyy/mm/dd HH:MM:SS - yyyy/mm/dd HH:MM:SS IPアドレスorホスト名 ポート番号 NG
.
.
.

標準出力に上記を出力。正常に接続できたら「OK」、それ以外はすべて「NG」とする。接続時のメッセージは/dev/nullに捨てずにログファイルに記録する。

サンプルコード

portscan.sh
#!/bin/sh

logfile=portscan.log
portlist="$1"

if [ $# -lt 1 ]; then
    echo "Usage: `basename $0` portlist"
    exit 0
fi

if [ ! -r ${portlist} ]; then
    echo "${portlist} can not read."
    exit 1
fi

echo `date +'%Y/%m/%d %H:%M:%S'` `basename $0` scanstart >> ${logfile}

while read line
do
    # 空行とコメント行を無視する
    echo ${line} | grep -E -e '^[[:blank:]]*$' -e '^[[:blank:]]*#' >/dev/null
    if [ $? -eq 0 ]; then
        continue
    fi

    echo -e "`date +'%Y/%m/%d %H:%M:%S'`\c"

    # IPアドレス(ホスト名)とポート番号を取得
    dest=`echo ${line} | awk '{print $1,$2}'`
    # telnetでログインしたらすぐ切断
    (sleep 1; echo -e "\x1d"; sleep 1; echo quit) | telnet ${dest} >> ${logfile} 2>&1

    # 接続結果を表示
    if [ $? -eq 0 ]; then
        echo " - `date +'%Y/%m/%d %H:%M:%S'` OK"
    else
        echo " - `date +'%Y/%m/%d %H:%M:%S'` NG"
    fi

done < ${portlist}

echo `date +'%Y/%m/%d %H:%M:%S'` `basename $0` scanend >> ${logfile}

sleep 1については、応答時間以上の値を指定する必要がある。過去実績を参考にするのが良い。
echo -e "\x1d"はbashのechoコマンドの仕様に合わせて書いている。仕事で使っているOSのechoがSystem V仕様である場合-eは不要なため、コマンドはecho "\x1d"となる。様々な環境で使用する場合は、echoの差異を吸収する関数を作成しても良いかもしれない。
ちなみに\x1dCtrl+]のASCII制御文字(16進数)である。