はじめに
さて、外出先で自宅のサーバにログインしたくなったとき皆様はどうしていますか? モバイル環境から自宅に対してVPNを貼ったり、SoftEtherを使ったり、SSHを使用して暗号化を施してログインしたり、と様々な方法があると思います。
VPNやSoftEtherを利用する場合、導入段階で面倒な作業を行う必要があるため、私はSSHを使っています。しかし、動的IPから自宅にSSHで入る場合、SSHのポートを外部に開かなければいけません。
昨今、個人・企業問わずSSHのポートに対して総当り攻撃が増えています。きちんとSSHを設定して秘密鍵交換方式にしていれば総当り攻撃も回避できるのですが、それに伴うログの量やサーバ負荷などを考えると、閉じていた方が無難という判断もできます。しかし、どうしてもSSHポートから入りたい場面というのは出てきます。
そんなわけで、シェル初心者ですが以下のスクリプトを作成してみました。
このスクリプトを使用すると、TCPWrapperに対応するサービスを「POP Before」(POP認証後、接続IPに対し許可を与える)化することが可能になります。
対象読者
本稿では、ある程度シェルスクリプトを使うことができる、初心者から中級者を読者として想定しています。
必要な環境
最近のUNIX互換OSで動作するはずですが、私の環境ではRedhat Linux 8で動作確認を行っています。
動作するには以下のパッケージがインストールされている必要があります。
特にバージョン差異による誤動作などは無いとは思いますが、念のためご自身の環境でデバッグモードによるテスト動作をお勧めします。
/bin/sh -x ./access-allow.sh
初期設定
ソース上部にある「Default setting. 」の部分を、お使いの環境に合わせてカスタマイズしてください。
# Default setting. # DBPATH=<drac db file path> DBPATH=/etc/mail/dracd.db # FILEPATH=<hosts.allow file path> FILEPATH=/etc/hosts.allow # FILEPATH=<hosts.allow backup file path> FILEPATH2=/etc/hosts.allow.bak # Temporary file path TMP=/tmp/access-allow TMP2=/tmp/access-allow.bak SCR=/tmp/access-allow.scr # LOGFILE=<log file path> LOGFILE=/var/log/access-allow.log # TIME=<Sleep sec time> TIME=20 # SERVICE=<service or daemon name> # Please input service corresponding to TCP Wrapper. SERVICE=in.sshd # Default setting end.
上記以外では以下のことが必要です。
- 既存の「hosts.allow」に以下の行を追加
- できれば、既存「hosts.allow」ファイルのバックアップ
# access-allow
初期設定時の注意
一時ファイルのファイル名は、なるべく推測しにくい名前にすることをお勧めします。
# Temporary file path TMP=/tmp/access-allow TMP2=/tmp/access-allow.bak SCR=/tmp/access-allow.scr
使用方法
root権限で、バックグラウンドで実行してください。
# ./access-allow.sh &
基本動作
シェルスクリプトを作成した経験がある方ならば、ソースを見ればわかるとは思いますが、以下のようになっています。
- DBから抽出
- 前回の記録との照合
- 差異があった場合は前回「hosts.allow」に追加した分を削除して、今回の内容を追加
- ログの書き出し
- 20秒間のスリープ(デフォルトでは20秒)
- 「1.」に戻る
ソースコード
#!/bin/sh
# POPbeforeETCSERVICE Script.
# Version 1.2
# Copyright (c) 2005 Mappi <info@mappi-daily.net>
# All rights reserved.
# This script is the one to give the access permit in cooperation
# with dracd as for service corresponding to TCP Wrapper.
PATH=/bin:/usr/bin:/sbin:/usr/sbin;export PATH
# Default setting.
# DBPATH=<drac db file path>
DBPATH=/etc/mail/dracd.db
# FILEPATH=<hosts.allow file path>
FILEPATH=/etc/hosts.allow
# FILEPATH=<hosts.allow backup file path>
FILEPATH2=/etc/hosts.allow.bak
# Temporary file path
TMP=/tmp/access-allow
TMP2=/tmp/access-allow.bak
SCR=/tmp/access-allow.scr
# LOGFILE=<log file path>
LOGFILE=/var/log/access-allow.log
# TIME=<Sleep sec time>
TIME=20
# SERVICE=<service or daemon name>
# Please input service corresponding to TCP Wrapper.
SERVICE=in.sshd
# Default setting end.
# Environmental investigation
if [ ! "(" -s ${DBPATH} ")" ];then
echo "${0}:${DBPATH}: No such file or directory"
echo "${0}:${DBPATH}: No such file or directory" >> ${LOGFILE}
exit 1
fi
if [ ! "(" -s ${FILEPATH} ")" ];then
echo "${0}:${FILEPATH}: No such file or directory"
echo "${0}:${FILEPATH}: No such file or directory" >> ${LOGFILE}
exit 1
fi
# Start log output
echo "`date` access-allow.sh start..." >> ${LOGFILE}
# Delete temporary files.
if [ ${TMP} ];then
rm -f ${TMP}
fi
# Main processing.
while [ "TRUE" ]
do
COUNT=`db33_dump -p ${DBPATH} |
egrep "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | wc -l |
sed s/^[[:space:]]*//g`
CT=1
until [ "${CT}" -gt "${COUNT}" ]
do
echo -n "`db33_dump -p ${DBPATH} |
egrep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | sed -n ${CT}p` " >> ${TMP}
CT=`expr ${CT} + 1`
done
if [ "`cat ${TMP}`" != "`cat ${TMP2}`" ];then
echo "/access-allow/a\\" > ${SCR}
echo -n "${SERVICE} : " >> ${SCR}
cat ${TMP} >> ${SCR}
cp ${FILEPATH} ${FILEPATH2}
sed /${SERVICE}/d ${FILEPATH2} > ${FILEPATH}
cp ${FILEPATH} ${FILEPATH2}
sed -f ${SCR} ${FILEPATH2} > ${FILEPATH}
echo "`date` add `cat ${TMP}`" >> ${LOGFILE}
fi
mv ${TMP} ${TMP2}
sleep ${TIME}
done
最後に
今回、CodeZineに投稿したわけは勉強としての意味合いが強く、はっきり言って自分のソースコードはスマートではありません。もっとスマートなやり方を思いつく読者の方がたくさんいると思います。
拙い記事ですが、ここに投稿したことによって自分自身がさらに精進できればいいなと思っています。皆様の暖かい意見をお待ちしております。

egrep "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | wc -l |