【Teratermマクロ】リモートサーバー間で疎通確認する

# 初めに
リモートサーバー間の疎通確認をローカル端末から自動で実施するために書いたTeratermマクロのメモ。動きとしてはローカル端末上に用意した通信要件が書かれたファイルに従って通信元サーバーへログイン後、通信元サーバーから通信先サーバーに対して`telnet`で疎通確認しその結果をローカル端末上に書き出すという簡単なもの。

# 環境
ローカル端末
　- Windows7
　- Teraterm 4.77
リモートサーバー
　- AIX 7.1

# 前提
### telnetでの疎通確認結果:
前提として、疎通確認の結果は今回以下のように分類する。これは環境によって違うと思うので適宜調整する。


その1. 応答が返ってこない
以下のように`試行中...`のまま応答が返って来ない場合。FWやIPsecで遮られている等が考えられる。

```
# telnet <dst_ip> <port>
試行中...
```

その2. リモート・ホストは拒絶しました。
以下のように`リモート・ホストは拒絶しました。`のメッセージが返ってくる場合。FWがRST返している、ポートがLISTENになっていない等が考えられる。

```
# telnet <dst_ip> <port>
試行中...
telnet: 接続: connect 操作をしようとしましたが、リモート・ホストは拒絶しました。
```

その3. 接続
問題なくTCPコネクションが張られる場合。

```
# telnet <dst_ip> <port>
試行中...
<dst_ip> に接続されました。
エスケープ文字は '^]' です。
telnet>
```

### 入出力：
通信要件が書かれたcsvファイルを読み込ませる。フォーマットは以下を想定。

```
<連番>,<ログインIP>,<通信元IP>,<通信先IP>,<ポート番号>
```

- 連番：各行の通し番号。ログファイル名に使う。
- ログインIP：通信元サーバーにローカル端末からログインする際のIPアドレス
- 通信元IP：通信元サーバーのIPアドレス
- 通信先IP：通信先サーバーのIPアドレス
- ポート番号：通信先のポート番号

出力は、読み込ませるcsvファイルに疎通確認結果を示す番号（下記コードの変数flgの部分を参照）列を追記したものを出力ファイルとする。

# コード
以下にコードをメモ。PowerHAを組んでいる場合、VIPを保持していると通信元のIPアドレスはVIPとなる（設定により異なる）ので、プライマリかどうかを確認するコマンドを途中で実行している。

```ttl:connection-ckecker.ttl
;;; 事前定義
inFile = '<input File path>¥checklist.csv'
outFile = '<output File path>¥summary.csv'
logDir = '<log directory path>'
loginUser = '<user name>'
loginPass = '<password>'
rootPass = '<root password>'
separator = ','
timeout = 1

;;; inFile読み込み準備
fileopen fh inFile 0

;;; outFile書き出し準備
fileopen fh2 outFile 0

while 1
    ;;; 1行ずつ処理
    filereadln fh line
    
    if result then
        break
    endif

    ;==============================================
    ; 初期準備 
    ;==============================================
    ;;; 行をカンマで分解
    strsplit line separator
    ;;; 連番
    num = groupmatchstr1
    ;;; ログイン（通信元）サーバーIP
    loginIP = groupmatchstr2
    ;;; 通信先サーバーIP
    toIP = groupmatchstr4
    ;;; ポート番号
    port = groupmatchstr5

    ;;; ログインサーバーへのログイン用コマンド生成
    sprintf2 logincmd '%s /nossh /KR=SJIS /KT=SJIS' loginIP
    ;;; 疎通確認用コマンド生成
    sprintf2 telnetcmd 'telnet %s %s' toIP port
    ;;; ログファイル名生成
    getdate date '%Y%m%d-%H%M%S'
    sprintf2 logFile '%s¥connection-checker_No%s_%s.log' logDir number date

    ;==============================================
    ; ログインサーバーへログイン
    ;==============================================
    ;;; ログイン
    connect logincmd
    ;;; ログ取得開始
    logopen logFile 0 1 0 1 1

    wait 'login:'
    sendln loginUser

    wait 'Password:'
    sendln loginPass

    wait '$'

    ;;; ホスト名をバナー表示
    sendln 'banner `hostname`'

    wait '$'

    sendln 'su -'

    wait 'パスワード:'
    sendln rootPass

    wait '#'

    ;;; PowerHAの状況を表示
    sendln '/usr/es/sbin/cluster/utilities/cldump | tail -n 4'

    wait '#'

    sendln 'exit'

    wait '$'

    ;;; 同期通信モードに設定
    setsync 1

    ;==============================================
    ; 疎通確認
    ;==============================================
    ;;; 疎通確認
    sendln telnetcmd
    pause 2

    ;;; 結果により分岐させる
    wait "$" "エスケープ文字は '^]' です。"

    ;;; timeoutした場合（前提で言うと、その1）
    if result = 0 then
        send #3
        sendln "echo 'Result is 1. Time out.'"
        flg = '1'

    ;;; 前提で言うと、その2
    elseif result = 1 then
        sendln "echo 'Result is 2. Remote host connection refused.'"
        flg = '2'

    ;;; 前提で言うと、その3
    elseif result = 2 then
        ;;; 相手からクローズされたか確認
        wait '$'

        ;;; 接続中の場合
        if result = 0 then
            ;;; クローズする
            send #$1D
            sendln ''
            pause 1
            wait 'telnet>'
            sendln 'q'
            wait '$'
            sendln "echo 'Result is 3. Connection is established.'"
        ;;; 相手から即クローズされた場合
        elseif result = 1 then
            sendln "echo 'Result is 3. Connection was established but closed immediately.'"
        endif
        
        flg = '3'
    endif

    ;==============================================
    ; 結果書き出し
    ;==============================================
    sprintf2 outstr '%s,%s' line flg
    filewriteln fh2 outstr

    ;==============================================
    ; 後処理
    ;==============================================    
    ;;; ログインサーバーからログアウト
    sendln 'exit'
    puse 1

    ;;; ログを閉じる
    logclose
endwhile

;;; ファイルハンドラをクローズ
fileclose fh
fileclose fh2

```