port forward の background化
以前、Mac OSX で port forward を実現するエントリーを書いた。
http://d.hatena.ne.jp/tono-p/20100619/p1
たまたま radiko 関連で port forward を行っているエントリーを見つけ、そこで ssh が起動してなかったら繋ぐという shell script を cron で5分ごとに行っていたので、これを試してみることにした。このエントリーは FreeBDS の環境らしいが同じことは Mac OSX でも可能なはずだ。
http://w.vmeta.jp/tdiary/?date=20100921#p01
#!/bin/sh isAlive=`ps -x|grep "ssh -t -t -l username"|wc -l` if [ $isAlive -eq 1 ]; then echo -n "Connecting ssh for ssh_server..." ssh -t -t -l username \ -L 3143:mail_server:143 \ -L 3110:mail_server:110 \ -L 3025:mail_server:25 \ ssh_server \ -i ~username/.ssh/id_rsa \ && echo 'OK!' else echo "ssh for ssh_server is alive." fi
script はこんな感じになった。最初に ssh のプロセスが動いているかどうかを確認してカウント結果を変数に格納している。その数が 1 であれば ssh を実行し、それ以外は何もしないという処理内容。何故 1 にしているかというと、grep ssh のプロセスもカウントしてしまう為。自分自信を含めないオプションがあるのだろうか? echo はログに結果を残す為のものだ。
terminal から script を実行すると動くのだが、cron で動かそうとすると、Pseudo-terminal will not be allocated because stdin is not a terminal. というエラーメッセージがある。この解決方法はここにあった。ssh に -t のオプションをダブルで付ける。
http://takat.exblog.jp/12216326/
cron の登録は crontab -e で開いたファイルを編集。
*/5 * * * * /path/to/script/pf_start
これで、何もしなくても自動的に port forward が行われるようになった。しかもバックグラウンドで動き余計なターミナルも開かない。
追記
ps -xw|grep "ssh ...." の場合、ssh を実行したが接続状態になっていない場合があったり、複数の ssh プロセスが残ってカウントが期待した数字にならない場合があったので、判定方法を見直した。netstat は 各 port の状態が検索出来るので、ssh の接続が確立している場合のみ表示される文字列を抽出している。
/usr/sbin/netstat -a -n|grep 127.0.0.1.3143|wc -l
さらに、オフラインの時には ssh の接続は無駄なので起動しないよう判定を加えた。もっとスマートな判定方法がありそうな気がするが、実用上は問題ないだろう。
/sbin/ping -c 1 time.gov|grep "packets transmitted"|wc -l
この結果完成した shell script は以下のようなものだ。
#!/bin/sh isConnected=`/sbin/ping -c 1 time.gov|grep "packets transmitted"|wc -l` isAlive=`/usr/sbin/netstat -a -n|grep 127.0.0.1.3143|wc -l` if [ $isConnected -eq 1 ]; then if [ $isAlive -eq 1 ]; then echo "ssh for ssh_server is alive." else echo -n "Connecting ssh for ssh_server..." ssh -t -t -l username \ -L 3143:mail_server:143 \ -L 3110:mail_server:110 \ -L 3025:mail_server:25 \ -L 3080:proxy_server:80 \ ssh_server \ -i ~username/.ssh/id_rsa \ && echo 'OK!' fi else echo "network is not active." fi