Kermitを使う


 明日いっぱいで旧鯖ともお別れである。サービスもSSH以外はほぼ止めてある。
 が、何か取りこぼしは無いかなー、と思って眺めていると、あったあった。このファイルは拾っておくか、的な物が。早速FTPで接続。出来ない。止めてるしな。パスワード知らないユーザーのディレクトリに送りたいからscpも困るな…。ローカルへのscpをしようにも、これ俺のディレクトリじゃないしなあ(笑)。HTTPアップロードとかもちょっとアレだし。
 はっ。Kermitがあるじゃナイデスカ。よし、kermit -P -iで、send 何とか.tar.gzで、あとは受信だな!
 ちゃんと転送されてます。キモーイ。オソーイ。マジオソーイ。
 scpで俺のディレクトリに送ってsuしてどうにかすれば良かったよね、というオチで。

 つーかrootなんだからコピー元を俺のディレクトリに移してローカルにscpするなり何なりどうとでもなっただろーが的な。つまり、Kermitを試したかっただけだろうな。ZMODEMならもっと懐かしくなれたかもね!


NP12にUbuntuを入れようとして苦悩する


 NP12が余っているので、WINSサーバも欲しいしー、W32TimeじゃなくNTPDも欲しいしー、などと思い始める。よし、Linuxとデュアルブートだ。VPSではCentOSばかり使ったが、今度はUbuntuでも試してみようか。
 でも、手元にUSBメモリなど無い。USB接続のCDドライブなども無い。USBハードディスクはある。これで何とかなるのか?
 とりあえず、NP12のHDDをPuran Defragで整地して、お馴染みのコンパネ→管理ツール→コンピュータの管理→ディスクの管理からパーティションを20GBほど縮小し、Ubuntu用の領域を作っておく。ここまでは楽勝。
 で、あとはとにかく無理矢理インストーラーを起動させたらいいんじゃね、と思って、初期化したUSBハードディスクに32GBのパーティションを一つだけ作り、UNetbootinで強制的にISOを書き込んだが、起動しない。が、Universal-USB-Installerでフォーマットさせつつこれまた強制的に書き込んだら、何とかインストーラーが起動はした。CD-ROMが読めないよ、とか言われて頓挫したが。
 うーむ。Live CD版をNP12の空き領域に書き込んで、MBRに適当なブートローダーを突っ込んで、起動したら適当に調整、とかかなあ…。思ったよりめんどくさいなー。


SSHクライアントの接続元を半自動的にホワイトリスト登録してみる


 まあ、Fail2banの話の続きですな。「完結編の続編とか普通出るだろ」という宇宙戦艦的思想で。
 つっても大した話じゃないんだけど。ホワイトリストに追加するスクリプトを書いてみた、というだけ。色々切り詰めて抜き出すとこんな感じ。

#!/usr/bin/python
import os
import commands

ssh_client_address = os.environ['SSH_CLIENT'].split()[0]

def regist_fail2ban():
    ignore = commands.getoutput('fail2ban-client get fail2ban ignoreip')
    ignore_list = [x.split()[-1] for x in ignore.splitlines()[1:]]
    if ssh_client_address in ignore_list:
        print 'Already ignored.'
    else:
        os.system('fail2ban-client set fail2ban addignoreip ' + ssh_client_address)

def main():
    regist_fail2ban()

if __name__ == '__main__':
    main()

 適当に関数を増やせば、iptablesとかにも応用出来るかな。間違ってsshじゃないシェルで使っても、os.environのとこでKeyError例外貰って即終了なので問題無し。
 こいつを適当に実行権限持たせておいて、sshでログインしたら実行しておく、みたいな使い方を想定した感じだけど、もっと便利になる手法はいくらでもありそうだ。Web UIとか、DDNSとcronの組み合わせとか。作るのめんどいけど。DDNSは既に対応してる人なら一番簡単だろうけどなあ。

追記:
 アドレスが変わった時に旧アドレスの登録抹消などの処理はしないので、真面目に気になってきたら修正するかも。


Fail2ban完結編


 予想外に延々と続いたFail2banの記事も大団円を迎えようとしていた。ような。気が。
 ログを見たところ、自己監視も機能しているようなので、そろそろ設定をまとめて書いてみる。

  • fail2ban.conflogtargetを/var/log/fail2ban.logに変更。自己監視をしないなら別にどうでもいい設定。syslogにまとめる意味も別に無いが。EPELから拾った奴だと、logrotateはどちらでも動作する設定になっているようだ。
  • 自己監視を設定。Fail2ban monitoring Fail2ban参照。しつこい奴を少し長めに追放する設定である。
    長期的かつ全portの遮断になるので、誤動作を考えると安易にお勧めはしにくい。さくらのVPSはシリアルコンソールがあるから最悪何とかなるだろー、という考えで導入している。fail2ban-client set fail2ban addignoreip x.x.x.xで管理端末をホワイトリストに入れておく、などの安全策はお勧めだが、手作業が嫌いな俺は多分やらない。重複チェックが無いので自動化も少し面倒。
    なお、原文でも触れられているが、アクションの種類によっては問題が出る。要は、「ban→ban→unban→unban」という流れなので、二重banを認識しない機構だと一回目のunbanでbanが全て解除されてしまうのだ。iptables系アクションはnameが異なるbanを別のチェーンに登録するので、nameがユニークなら問題は起きないはず。
  • 古いカーネルの問題らしいが、iptables系アクションが初期化で失敗する現象(Fail2banのログにERRORとかreturned 100とか出る奴)を確認したので、チェーンを自前で準備する形式にする。
    具体的には、利用したいaction.d/iptables*.confのコピーを取り、actionstartactionstopを空白にした別バージョンを作ってjail.confaction=ではそちらを使うように指定し、actionstartに書かれていたコードを自前で解釈実行してservice iptables saveをしておく。
    actionstartの自前解釈は、例えばjail.confの中でaction = iptables-allports[name=fail2ban]action = iptables-allports[name=ssh]を利用しているなら、

    # iptables -N fail2ban-fail2ban
    # iptables -A fail2ban-fail2ban -j RETURN
    # iptables -I INPUT -p tcp -j fail2ban-fail2ban
    # iptables -N fail2ban-ssh
    # iptables -A fail2ban-ssh -j RETURN
    # iptables -I INPUT -p tcp -j fail2ban-ssh

    のように、名前の部分を変えてコマンドを実行する感じ。他にもあるなら適宜追加で。終わったら忘れずにservice iptables save
    つーか問題が出ないカーネルを使ってればこんなことしなくていい。

  • フィルタも適当に調整した。確か、PostfixとDovecotの監視を一つのフィルタにまとめて、554554 5\.7\.1にしただけ。
  • Shorewallは結局使っていない。

 こんなもんだろうか。
 無駄に手間を掛けた感もあるが、シンプルな設計なので触りやすかった。ただ、自作フィルタはインジェクションによるDoSも少し気になるが。あと開発止まってるような気もするが、まあ、フィルタとアクションを工夫すればどうにでもなるかも。
 IPv6への対応は、Logwatchがうざくなったらまた考えようと思う。Fail2banはセキュリティというよりLogwatch対策で入れているのだし。ははは。


Fail2banの問題を確認する


 どうも、チェーン生成が絡んだ場合、iptablesを立て続けに操作した時に「そんなチェーン無いし」とか言われるっぽい。多分。それが起きると、Fail2banのログに

fail2ban.actions.action: ERROR  iptables -N fail2ban-何とか
iptables -A fail2ban-何とか -j RETURN
iptables -I INPUT -p tcp -j fail2ban-何とか returned 100

などと吐き出される。また、service iptables statusまたはiptables -L -nを実行すると、出力にChain fail2ban-何とか (0 references)が含まれている。ここも本来は(1 references)でなければならない。
 よって、小手先の対応としては、Fail2banを起動したらすぐにFail2banのログかiptablesのステータスを確認し、エラーが出ていたら出なくなるまでfail2ban-client reloadを繰り返し実行、くらいで大丈夫だと思う。または壊れている定義を自前で修復するか。
 というより、そんなアホな作業をしたくなかったので、iptables系アクションのiptables -N fail2ban-<name>の次の行にperl -e 'select undef,undef,undef,0.1'とか短時間のスリープを埋め込んでやれば幸せになるんじゃね、と思ったのだが、全然役に立たなかったのでやめた。
 つーか、チェーン生成は事前に自前でやってservice iptables saveしといて、iptables系アクションのチェーン生成削除処理を削除するのが一番安定だな。そうしよう。ついでに-j DROP-j REJECT --reject-with icmp-admin-prohibitedに変更してみたけど、大抵は帯域の無駄という話もあったり。

 などとiptables系のアクションを弄っていたら、次に思ったのが「ここにip6tablesへの分岐処理とか埋めたら普通にIPv6対応になるんじゃね?」であった。
 が、Fail2banは、ログからIPv6アドレスを拾ってくれるのだろうか。公式Wikiのマニュアルを見てみると、<HOST>のマッチングは

(?:::f{4,6}:)?(?P<host>\S+)

となっているが、添付filterのコメントには

(?:::f{4,6}:)?(?P<host>[\w\-.^_]+)

とある。まあ、多分駄目だろうな。
 とは言っても、要するにPythonの名前付きキャプチャで拾ってるだけ、ということらしいから、filterも自前で

(?:::f{4,6}:)?(?P<host>[\w\-.^_:]+)

とかに書き換えればいいのだけど。

 ということで、意外と簡単に何とかなりそうだなー、と思ったが、IPv6ホストをbanするのって単純なソースアドレスマッチングで行けるのかなー、とか考えてるうちに、実際に困り始めたらやればいいかー、と思ったのであった。

追記:
 確かにREJECTは帯域の無駄だった。むしろバルクメーラー的にはメモリ節約出来て嬉しいという逆効果の予感も。