古いMacBookの延命策

2006年の夏に購入したMacBook1,1は、その翌年には1年間の保証期間が切れるのを待っていたかのようにDVDドライブが壊れ、さらに数年後にはバッテリーの膨張であわやハードウェアの損傷か?とういトラブルが起きた。しかたないから蓋と一体型のバッテリーをはがし取り、ガムテでなんとかその体裁を維持している。

そんなMac君もお茶の間の娯楽用PCとしてはインターネットや動画再生でたくさん活躍してくれました。そしてこれからも充分使えそうなほど、前出のハードウェア以外は全く問題なく元気ハツラツなMac君。さすがアップル!伊達にニュートンにかじられちゃいません。

話は飛びますが、マイクロソフトはお釈迦さまの生まれた日(日本時間では4/9)にWindowsXPのサポートを終了するというじゃぁありませんか。サポート終了後も使い続けられるXPを狙って、よりいっそう攻撃が増加するという予想もされてますが、被害に遭わないためにも早めに使用をやめた方が無難かもしれません。

娯楽目的ではMacBookWindowsXPメインでしか使用してこなかったバチ当たりな私ですが、今後Mac OS-X一本でMac君と付き合わなければなりません。とは言うものの購入当時のタイガーのままバージョンアップしてないので最新の動画再生ソフトなどがインストールできません。これではOS-Xも使い続けられず、このままではジャンク同然です。

Webの表示&動作テストの用途としての当初の役目を終えて以降、Mac君にはなんにも手当をしていなかったのが今になって悔やまれます。かといっていまさらOSをアップグレードするほどの価値もない。中古ノートを買うための資金調達でヤクオフに出しても買い叩かれるのがオチ。

Mac Book 1,1 にUbuntuを!

で、現在インストールしているXPを削除してLinuxがインストールできないか検索したらたくさんヒットする!おお「捨てる神あれば拾う神あり」ですね。中古のThinkPadでも買おうかと動かしはじめてた食指を止めることにした。

記事の多さではUbuntuのインストールが圧倒的で、短時間で確実にセットアップしたい私にとっては選択肢はそれしかなさそう。

https://help.ubuntu.com/community/MacBook1-1/Lucid を見ると少々問題はありそうだけど充分使えそうな雰囲気。XPのときもキーボードなどいろいろ不便な思いをしてきたわけだし。簡単にUbuntuがインストールできれば言うことなしなのだ。

インストールに関しては https://help.ubuntu.com/community/MactelSupportTeam/AppleIntelInstallation に記されている。Ubuntuのシングルブートも可能らしいが、ここはやはり何かあったときのためにデュアルブートの道を選択する。

まずブートローダーの rEFIt をインストールする。OS-Xのバージョンが古すぎてインストールできるかドキドキしたがあっさり通った。

BootCampを起動して一度XPの領域を削除してから再度Linux用のディスクスペースを確保しなおす。このときBootCampに試用期限切れで使えないと怒られるww。当時ベータバージョンで配布されていたものなのでしかたないのか?Macの日付を2007年に戻してから起動し直して無事にクリア。

あとはUbuntuのisoイメージからインストーラを起動できればOK。最新のバージョンにしたいところをぐっとこらえて、上のリンク先にあるように10.04をインストールしてからバージョンアップしていくのが無難そう。それより高いバージョンではドライバーがサポートされてないという記事も見たような気がするし、(直接関係ないけど)以前 Pentium M のマイクロPCにUbuntuサーバをインストールしようとしたときpaeサポートの問題で10.04.4LTSをインストールしてから順次バージョンアップしなければならない事もあったからだ。

光学ドライブが壊れているので、USB接続のCD/DVDドライブにUbuntuのisoイメージディスクを入れてMacを再起動…。ところが黒い画面のまま、いつになってもドライブから読み込みが始まらない。他のマシンのインストールに使った違うバージョンのUbuntuでやっても状況は変わらず。やはり、内蔵ドライブじゃないと起動できないのか?USBメモリーからはどうかと思って、Universal USB Installerを使って作成したが、これもダメだった。

あれやこれや検索ワードを変えてググってやっとたどり着いたのがココ http://gfs.sourceforge.net/wiki/index.php/Live_Ubuntu_Gerris_distribution

私と同じ境遇(内蔵光学ドライブが壊れている)の人がこれを解決してるじゃぁないですか!一筋の光明。

要はパーティション無しのライブUSBインストールイメージを作成すればい良いということらしい。それってどういうこと?

いろいろ考えたり戸惑っていても時間がもったいないので実行あるのみ。(※以下は備忘録を兼ねて記していますが、なにか抜けがあったらご容赦を)

Ubuntuの起動USBメモリーを作る

仕事で使ってるUbuntuマシンがあるので私はそれを使ったが、Ubuntu環境が無い場合はMacでも出来そうかな。ここでは上記サイトで紹介されているやりかたを、自分の環境で行った結果を記しています。

1. USBメモリーをフォーマットする

事前にUSBメモリがどこに割り当てられているのか調べる。アプリケーション >> ユーティリティ >> ディスク を起動して、デバイスのリストでUSBアイコンのドライブをクリックして、それに関するプロパティを見るか、$ sudo fdisk -l を実行して取得する。複数のUSBデバイスが接続されていると、どれがどれだか分からない場合もあるので要注意。

/dev/sdX のXの部分はそれぞれの環境に合わせて書き換える

$ sudo mkfs.vfat /dev/sdX -I
既にFATフォーマットされていたら、これはやらなくてもOK

2.Ubuntuのisoイメージをマウントする

はisoイメージのパス


$ sudo mkdir /media/ubuntu-disk
$ sudo mount -o loop /media/ubuntu-disk
mount: ブロックデバイス /ubuntu-ja-10.10-desktop-i386.iso は書き込み禁止です、読込み専用でマウントします

3.USBメモリーをマウントする


$ sudo mkdir /media/usb
$ sudo mount /dev/sdX /media/usb

4.USBメモリーにUbuntuファイルをコピーする

※コピーでちょっと怒られますが、無視して進めてOKみたい


$ cd /media/ubuntu-disk
$ sudo cp -rf casper disctree dists install pics pool preseed .disk /media/usb
cp: `disctree' を stat できません: そのようなファイルやディレクトリはありません
cp: シンボリックリンク `/media/usb/dists/stable' を作成できません: 許可されていない操作です
cp: シンボリックリンク `/media/usb/dists/unstable' を作成できません: 許可されていない操作です
$ sudo cp -rf isolinux /media/usb/syslinux
$ cd /media/usb/syslinux
$ sudo mv isolinux.cfg syslinux.cfg

5.ブート可能なUSBメモリーにする

自分の環境にはmtoolsがインストール済みだったので実際はsyslinuxだけをインストールした


$ sudo aptitude install syslinux mtools
$ cd ~
$ sudo umount /dev/sdX
$ sudo syslinux /dev/sdX

MacBookUbuntuをインストールする

上記手順で作成したUSBメモリーをMacBookに刺して電源を入れる。ブートマネージャーのrEFIt画面にOSのアイコンが並ぶ。左からリンゴ、ウィンドウズ(っぽいアイコン)、ペンギン。ペンギンをクリックする・・・・・・・ちゃんと起動する、やっとここまでこれた。

インストーラを起動して普通にインストール作業をすすめる。ただここで一つ失敗したことに気付かされた。スワップ用のパーティションを切っていなかったことだ(Boot Campを使ってパーティションを切るのは間違いだったかもと少し後悔する)。後戻りはめんどうなのでスワップ領域は後でファイルとして持つようにすることにして、Ubuntuのインストールを続行する。それから、キーボードに不安があったのでログイン時にパスワード入力を必要としない自動ログインを選んだ。

スワップ領域以外は躓きもなくすんなりインストールできた。USBメモリーを抜いて再起動すると、ブートローダーに表示されるリンゴアイコン右隣りのウィンドウズアイコンがペンギンに変わっている。ペンギンをクリックすると待望のUbuntu10が今までの苦労が嘘のようにフツーに立ち上がった。ホッとする。仕上げは12.04LTSへのアップグレードだ。

アップグレードはアップデートマネージャーに従って進めることにした。結局 10.04LTS ⇒ 11.04 ⇒ 11.10 ⇒ 12.04LTS の三回アップグレードすることになる。この途中、11.04でキーボードが意図しない文字を入力するようになり焦ったが、マウスを使って12.04LTSまで無事にインストールできた。自動ログインにしておいて良かったぁ。(※10.04LTSからアップデートするときには/etc/apt/sources.listファイルを修正する作業が発生する。本家からダウンロードしたisoならその必要は無いかも)

Ubuntuをインストールしたらやること

Ubuntu12までアップグレードできたらシステムのアップデートの他、やらなければならない事や、やっておいた方が良いことがいくつかある。

スワップ領域を確保する

インストール時にスワップ領域を作れなかったので、一応メモリーと同じ分だけ確保する。


$ sudo dd if=/dev/zero of=/swap bs=1G count=2
$ sudo chmod 600 /swap
$ sudo mkswap /swap
$ sudo swapon /swap
/etc/fstabに以下を追記する

/swap swap swap defaults 0 0
再起動してスワップ領域が確保されているか以下のコマンドを実行するか、システムモニターを開いて確認する。

$ cat /proc/swaps

イヤホンジャックから音声が出ないのをなんとかする

内蔵スピーカーからは音は出るが、イヤホンジャックにヘッドフォンを刺しても音が出ない。
ソフトウェアセンターでgnome-alsamixerをインストールする。それを起動するとSpeakerのスライダーが二つあるので、そのどちらかがイヤホンなのでいい感じになるまでスラーダーを上げればよい。

デスクトップを変更する

好き嫌いがあると思うが、私はUnityデスクトップが嫌いなのでいつも古いタイプに戻している。ソフトウェアセンターにてgnome-session-fallbackを検索してそれをインストールする。

デスクトップをカスタマイズする

家族も使うので、デスクトップ画面にごみ箱やネットワークアイコンを表示させることにする。以下のコマンドを打つかソフトウェアセンターで「Advanced Settings」を検索してインストールする。


$ sudo apt-get install gnome-tweak-tool
起動するときは アプリケーション ⇒ システムツール ⇒ 設定 ⇒高度な設定をクリックする。gnome-tweak-toolを端末で打っても良い。表示されたダイアログのデスクトップタブをクリックして。デスクトップに置きたいアイコンのトグルスイッチをクリックしてONにする。

  • Have file manager handle the desktop ※これをONにしないとそれ以下の設定が有効にならない
  • Computer icon visible on desktop ※コンピュータアイコン
  • Home icon visible on desktop ※ホームアイコン
  • Networks Servers icon visible on the desktop ※ネットワークアイコン(我が家ではNASに置いてある動画ファイルを探すときに多少便利)
  • Trash icon visible on desktop ※ゴミ箱アイコン
  • Show mounted volumes on the desktop ※外付けUSB接続のHDDやメモリーなどがあった場合に表示されるアイコン
タッチパッドの動作設定

初期状態ではタッチパッドでのスクロールが無効になっているので、システム設定 ⇒ マウスとタッチパッドタッチパッドタブ を開いて「二指でのスクロール」を選択して「水平スクロールを有効にする」にもチェックを入れる。二指での操作が苦手ならエッジスクロールにすると良い。タッチパッドの上下左右の端で指を滑らすとスクロールするようになる。ちなみにデフォルトで二指タッチ(または二指+クリック)でコンテキストメニューは開けるようになってる。

快適なUbuntu on MacBook

セットアップ作業で別途ドライバーをインストールする必要性に迫られることもなく無事に終了。初期状態でファンクションキーの明暗調整や音量設定も機能するし、WindowsXPではハイバネートすると復帰できなかったが、Ubuntuではちゃんと機能している。Wi-Fiや有線Lanもまったく問題ない。以前のようにインターネットや動画再生に快適に使えるようになりました。またしばらく活躍してくれそうで〜す。

Snortのアラート検出時のログを見たい

SnortをIDSエンジンにしたBaseではいろんな角度からアラートを統計表示してくれるのでとても便利ですが、アラートが出た時点でなにが起きたのかを知りたくて、コマンドを叩いてログを検索することがたまにあります。しかし出先のスマホからはそれができない(できるけどやりたくないw)ので歯がゆい思いをすることがしばしば。いっそのことBaseからそれをやってしまおう(といってもリンクしてるだけですが)と思って作ったのがこのスクリプトです。SnortやBaseのインストールに関しては侵入検知ソフトSnortと周辺ツールをインストールするをご覧ください。

 BaseのTimestampに表示されている時分秒に合致するログを/var/log/から根こそぎ拾ってきて左画像のように表示します。Baseのソースを熟読する時間的余裕が無いのでまったくのスタンドアロンとしました。ですのでBase本体のように体裁良く表示するわけではありません。
 また、ログのパーミッションを甘くしたりとか、ツールを新たにインストールすることはせずに簡単に設置可能であることを目標としました。あくまでネットワークに繋がったPCの無い状況での簡易確認用途としてスマホから使うのが主な目的です。
 大量のアクセスおよびログが吐かれるサーバでは検索条件を新たに加えなければ使い物にならないかもしれません。
 一応ピックアップしたログの中でSource AddressとDest. Addressがハイライト表示して見やすくはなっています。ちなみにBase側の変更箇所はリンクの記述を追加する一ヶ所だけです。

主なファイル構成

Baseを設置したディレクトリ(/var/www/base)にfind_logディレクトリを作って以下のファイルを作成します。

  • cache/ (キャッシュディレクトリ)
  • del_exp.sh (期限切れキャッシュファイルを削除する)
  • grep_log_dt.sh (指定された日時のログファイルを検索する)
  • grep_result.txt (検索した結果を一時的に保存するファイル)
  • index.php (ログ表示ページ)
  • jquery-2.0.2.min.js (jquery、適当なやつをダウンロード)
  • target_datetime (タイムスタンプを一時保存するファイル)

 

処理の流れ
BaseのTimestampのリンクをクリックする。
↓
find_log/index.php キャッシュファイルがなかったらタイムスタンプをtarget_datetimeに書き込んで、grep_log_dt.shがキャッシュファイルを生成するのを待つ(指定秒間隔のリフレッシュ)。キャッシュファイルが既にあったらそれを表示する。
↓
find_log/grep_log_dt.sh 定時実行してtarget_datetimeのタイムスタンプを読み込んで、ログファイルを検索、結果をキャッシュファイルに書き込む。target_datetimeに時刻が書き込まれていなかったら終了する。

 

Baseの改造

Baseディレクトリ直下のbase_qry_sqlcalls.phpの225行目あたり

qroPrintEntry($myrow[3]);
 ↓
qroPrintEntry("<a href='./find_log/index.php?timestamp=$myrow[3]&amp;sip=$current_sip&amp;dip=$current_dip'>".$myrow[3]."</a>");

 

cache/

キャッシュディレクトリにはBaseのタイムスタンプに紐づくキャッシュファイルを作成します。命名規則は、例えば"2013-12-31 23:59:59"のスペースの部分を'_'(アンダースコア)に置換した"2013-12-31_23:59:59"とする。
 

del_exp.sh

機能:キャッシュファイルの生成日から指定日数を過ぎたものを削除します。
crontabに
0 0 * * * /var/www/base/find_log/del_exp.sh
を記述して毎日実行。


#!/bin/bash
export LANG=en
CACHE_DIR="/var/www/base/find_log/cache/"
LIMIT=`date '+%s' -d '30 days ago'`
for FILE in `find ${CACHE_DIR} -type f | \
grep -e "[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}"`
do
if [ `date '+%s' -r ${FILE}` -lt ${LIMIT} ]; then
rm -f ${FILE}
fi
done
exit 0
 

grep_log_dt.sh

主な機能:各種のログの日付フォーマットでログファイルを検索して、合致する行をピックアップしてhtmlタグをつけてキャッシュファイルに書き出します。
検索対象日は、index.phpがtarget_datetimeファイルに書き出した日付をピックアップします。そのためにこのスクリプトを一定時間毎に走らせて、日付が書き出されたか常に監視します。とりあえず5秒間隔で動作するように、crontabを指定秒ごとに実行するで書いたような方法で記述しています。なにもしなければほとんど負荷はかからないのでさらに短い秒数でもいいかもしれません。ただcrontabにあの記述をづらずら書くのが気が引けるのと、スマホからのアクセスで大量に短時間に処理したいわけでもないので5秒間隔で充分かなと…。

#!/bin/bash
export LANG=en

# "YYYY-MM-DD hh:mm:ss"の19の文字列を取得する
DT_FILE="/var/www/base/find_log/target_datetime"
DT=`cut -c-19 ${DT_FILE}`
SIP=`cut -d' ' -f3 ${DT_FILE}`
DIP=`cut -d' ' -f4 ${DT_FILE}`
:> ${DT_FILE}

# ターゲットの日時の文字列がなかったら終了する
if [ ${#DT} -ne 19 ]; then
    exit 0
fi

# キャッシュファイルディレクトリ
CACHE_DIR="/var/www/base/find_log/cache/"

# キャッシュファイル名はスペースに_を入れて"YYYY-MM-DD_hh:mm:ss"とする
CACHE_FILE=`echo ${DT} | sed -e "s/\s/_/"`

# キャッシュディレクトリに既存のファイルがあるか検索する
EXIST_FILE=`find "${CACHE_DIR}" -name "${CACHE_FILE}"`

# 同じファイルがキャッシュにあったら処理を終了する
if [ ${#EXIST_FILE} -ne 0 ]; then
    exit 0
fi

# ログファイルディレクトリ
LOGDIR="/var/log/"

# grepした結果の一時保存ファイル
RES_FILE="/var/www/base/find_log/grep_result.txt"

# messages maillog 他 のフォーマット(冒頭に日付があって西暦がない) ***********
# e.g. "Jun  2 06:12:13"
FORMAT_1=`date -d "${DT}" "+%b %e %T"`

# apache access_log ssl_access_log ssl_request_log のフォーマット*************
# e.g. "08/Jun/2013:06:22:57"
FORMAT_2=`date -d "${DT}" "+%d/%b/%Y:%T"`

# apache error_log ssl_error_log のフォーマット*******************************
# e.g. "Wed Jun 19 10:20:44 2013"
FORMAT_3=`date -d "${DT}" "+%a %b %d %T %Y"`

# ↓ 検索文字列の先頭に"^"をつけてFORMAT_3にかぶらないようにする
grep -r "^${FORMAT_1}" "${LOGDIR}" >> ${RES_FILE}
grep -r "${FORMAT_2}" "${LOGDIR}" >> ${RES_FILE}
grep -r "${FORMAT_3}" "${LOGDIR}" >> ${RES_FILE}

CACHE_FILE=`echo ${DT} | sed -e "s/\s/_/"`

# ホスト名を取得する
SNM=`nslookup "${SIP}" | sed -n  "s/.*\(in-addr.arpa\tname = \)\(.*\)/\2/p"`
DNM=`nslookup "${DIP}" | sed -n  "s/.*\(in-addr.arpa\tname = \)\(.*\)/\2/p"`

# IPアドレスとホスト名を書き込む
TBL="<table class='iptbl'>"
TBL=${TBL}"<tr>"
TBL=${TBL}"<td class='title'>Source Address</td><td>${SIP}</td><td>:</td><td>${SNM}</td>"
TBL=${TBL}"</tr>"
TBL=${TBL}"<tr>"
TBL=${TBL}"<td class='title'>Dest. Address</td><td>${DIP}</td><td>:</td><td>${DNM}</td>"
TBL=${TBL}"</tr>"
TBL=${TBL}"</table>"
echo "${TBL}" > ${CACHE_DIR}${CACHE_FILE}

# 検索結果が得られなかったらメッセージ"No contents"を書き込む
RES=`cat ${RES_FILE}`
if [ ${#RES} -eq 0 ]; then
    echo "No contents" >> ${RES_FILE}
fi

# タグ(ログファイル名にdt 内容にdd)を埋め込んでキャッシュファイルに書き込む
while read line
do
    #echo ${line} | sed -e "s/\(^[^:]\+:\)\(.*$\)/<dt>\1<\/dt><dd>\2<\/dd>/g" >> ${CACHE_DIR}${CACHE_FILE}
    echo ${line} | sed -e "s/${SIP}/<span class='sip'>${SIP}<\/span>/g" \
                 | sed -e "s/${DIP}/<span class='dip'>${DIP}<\/span>/g" \
                 | sed -e "s/\(^[^:]\+:\)\(.*$\)/<dt>\1<\/dt><dd>\2<\/dd>/g" >> ${CACHE_DIR}${CACHE_FILE}
done < ${RES_FILE}

:> ${RES_FILE}

exit 0

 

index.php

主な機能:Baseから渡された日時の文字列に対応するキャッシュファイルがあったらそれを表示する。なかったらtarget_datetimeに日時を書き込んで、キャッシュファイルが生成されるのを待つ。
※Baseに戻るときはブラウザの戻るボタンを使用する。

<?php

#// キャッシュディレクトリ
$cache_dir = '/var/www/base/find_log/cache/';

#// grep対象の日時を書き込むファイル
$target_dt = '/var/www/base/find_log/target_datetime';

#// このファイルのURL
$base_url = 'https://EXAMPLE.EXA/base/find_log/index.php';

/*************************************************
* キャッシュファイルの存在チェック
*************************************************/
function existCacheFile ($timestamp = "", &$cache = "") {
    global $cache_dir;
    $cache = $cache_dir.strtr($timestamp, ' ', '_');
    return file_exists($cache);
}

/*************************************************
* Baseのタイムスタンプフォーマットかどうか
*************************************************/
function isTimestamp ($ts = '', &$matches = array('')) {
    return preg_match('/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/', $ts, $matches);
}

/*************************************************
* ipアドレスのフォーマットかどうか
*************************************************/
function isIpformat ($ip = '', &$matches = array('')) {
    return preg_match('/^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$/', $ip, $matches);
}

if (isTimestamp(htmlentities($_GET['timestamp'], ENT_QUOTES), $ts)) {
    $timestamp = $ts[0];
    if (!existCacheFile($timestamp)) {
        #// timestampがセットされていてキャッシュがなかったらtarget_datetimeファイルに書き込む
        isIpformat(htmlentities($_GET['sip'], ENT_QUOTES), $sip);
        isIpformat(htmlentities($_GET['dip'], ENT_QUOTES), $dip);
        if (!file_put_contents($target_dt, "$timestamp"." $sip[0]"." $dip[0]")) {
            echo "書き込みできませんでした";
        }
    }
} else {
    #// timestampがセットされていなかったらリフレッシュしてr_timestampに日時がセットされているはず
    if(!isTimestamp(htmlentities($_GET['r_timestamp'], ENT_QUOTES), $r_ts)) exit();
    $timestamp = $r_ts[0];
}

#// キャッシュファイルがまだ生成されていなかったら2秒後にリフレッシュする
if (!existCacheFile($timestamp)) {
    header("refresh:2;url=$base_url?r_timestamp=$timestamp");
}
?>

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script type="text/javascript" src="jquery-2.0.2.min.js"></script>
    <style type="text/css">
        table.iptbl {
            border: solid 1px #CCC;
            border-collapse: collapse;
        }
        table.iptbl tr {
            border: solid 1px #CCC;
        }
        table.iptbl .title {
            background: #CCC;
        }
        table.iptbl td {
            padding: 3px;
        }
        span.sip {
            background: #7fffd4;
        }
        span.dip {
            background: #fed0e0;
        }
        dl {
            width: 100%;
        }
        dt {
            font-size: 120%;
        }
        dd {
            width: 100%;
        }
    </style>
</head>
<body>
<?php
echo "<h1>Log finder</h1>";
echo "<dl>";
if (existCacheFile($timestamp, $cf)) {
    echo file_get_contents($cf);
} else {
    echo "ファイルを作成中";
}
echo "</dl>";
?>
</body>
<script type="text/javascript">
var dt_list = $('dt'),
    dlen = dt_list.length,
    dt_txt = '';
for (i=0; i<dlen; i+=1) {
    if (dt_txt !== (dt_txt = $(dt_list[i]).text())) {
        $(dt_list[i]).css({'background':'#ccc', 'margin-top':'20px', 'font-weight':'bolder', 'color':'#00f'});
    } else {
        $(dt_list[i]).css({'font-size':'5px', 'background':'#f0f0f0', 'color':'#fff'});
    }
}
</script>
</html>

 

jquery-2.0.2.min.js

特別な機能を使って無いので適当なjqueryファイルを置く。index.phpでインクルードしている。
 

target_datetime

index.phpが日時文字列を書き込んで、grep_log_dt.shが定時チェックして、書き込まれていたら読み込んでその後クリアされる。

侵入検知ソフトSnortと周辺ツールをインストールする

Webサービスとは直接関係しないシステムの構築の中で、Snortが一番面倒くさかったので、記憶が薄れないうちにに復習を兼ねて備忘録として記します。
構築環境:さくらVPS CentOS6.4(64bit)
インストールする主なソフト:Snort2.9.4.5, Barnyard2, Pulledpork, Base
インフラ構築のプロではないのでツッコミどころ満載かと思いますが、不備な点などあったらご指摘頂ければうれしいです。ただコメント(認証制)頂いても最近は反応が鈍いことが多いのであしからず。
※尚、Barnyard2がWarningを頻繁に出します。状況と対処法(暫定的)はBarnyard2のインストールで記しています。

Snortのインストール

本体をインストールする前にlibdnet-debuginfo-1.12-6.choon.centos6.x86_64.rpmがどこかにあると思うのでググってダウンロードしてインストールしておきます。

# rpm -ivh libdnet-debuginfo-1.12-6.choon.centos6.x86_64.rpm
場合によっては
libdnet-devel-1.12-6.el6.x86_64.rpm
libpcap-devel-1.0.0-6.20091201git117cb5.el6.x86_64.rpmが必要になるかもしれないので、適宜インストール。
http://www.snort.org/からSnort本体とdaqを/usr/local/src/などにダウンロード。
daqのインストール

# tar -zxvf daq-2.0.0.tar.gz
# cd daq-2.0.0
# ./configure
# make
# make install
# cd /usr/local/lib
# ldconfig –v /usr/local/lib
Snortのインストール

# tar -zxvf snort-2.9.4.5.tar.gz
# cd snort-2.9.4.5
# ./configure --enable-sourcefire
# make
# make install
# cd /usr/local/lib
# ldconfig –v /usr/local/lib
Snortルールと設定ファイルのインストール

# wget []http://www.snort.org/reg-rules/snortrules-snapshot-2945.tar.gz/[] -O snortrules-snapshot-2945.tar.gz
# cd /etc
# mkdir snort
# cd ./snort
# tar -zvxf /usr/local/src/snortrules-snapshot-2945.tar.gz
# cp ./etc/* .
# touch ./rules/white_list.rules ./rules/black_list.rules
Snortユーザーの追加

# groupadd -g 40000 snort
# useradd snort -u 40000 -d /var/log/snort -s /sbin/nologin -c SNORT_IDS –g snort
ファイル・ディレクトリの所有者の変更

# cd /etc/snort
# chown -R snort:snort *
# chown -R snort:snort /var/log/snort
/etc/snort/snort.confの編集 青字部分が修正箇所 左側の数字は行数

44 # Setup the network addresses you are protecting
45 ipvar HOME_NET XXX.XXX.XXX.XXX/24
46
47 # Set up the external network addresses. Leave as "any" in most situations
48 ipvar EXTERNAL_NET !$HOME_NET



101 # Path to your rules files (this can be a relative path)
102 # Note for Windows users: You are advised to make this an absolute path,
103 # such as: c:\snort\rules
104 var RULE_PATH /etc/snort/rules
105 var SO_RULE_PATH /etc/snort/so_rules
106 var PREPROC_RULE_PATH /etc/snort/preproc_rules
107
108 # If you are using reputation preprocessor set these
109 # Currently there is a bug with relative paths, they are relative to where snort is
110 # not relative to snort.conf like the above variables
111 # This is completely inconsistent with how other vars work, BUG 89986
112 # Set the absolute path appropriately
113 var WHITE_LIST_PATH /etc/snort/rules
114 var BLACK_LIST_PATH /etc/snort/rules
daqSnortディレクトリのパーミッションを変更する

# cd /usr/local/src
# chown -R snort:snort daq-2.0.0
# chmod -R 700 daq-2.0.0
# chown -R snort:snort snort-2.9.4.5
# chmod -R 700 snort-2.9.4.5
# chown -R snort:snort snort_dynamicsrc
# chmod -R 700 snort_dynamicsrc
初期化スクリプトをセットする
Snortサイトから環境に合った初期化スクリプトをダウンロードする

wget []http://s3.amazonaws.com/snort-org/www/assets/208/snort-centos-6x.sh[]
最初の`----- CUT HERE -----`の間をコピーしてファイル名snortで/etc/init.d/に置く

#!/bin/bash
#
# snort Start up the SNORT Intrusion Detection System daemon
#
# chkconfig: 2345 55 25
# description: SNORT is a Open Source Intrusion Detection System
# This service starts up the snort daemon.

・(略)

echo $"Usage: $0 {start|stop|restart|status}"
RETVAL=2
esac
exit $RETVAL

# chown snort:snort /etc/init.d/snort
# chmod 700 /etc/init.d/snort
次の`----- CUT HERE -----`の間をコピーしてファイル名snortで/etc/sysconfig/に置く

# /etc/sysconfig/snort
# $Id: snort.sysconfig,v 1.8 2003/09/19 05:18:12 dwittenb Exp $

#### General Configuration

・(略)

DUMP_APP=1
BINARY_LOG=1
NO_PACKET_LOG=0
PRINT_INTERFACE=0


# chown snort:snort /etc/sysconfig/snort
# chmod 700 /etc/sysconfig/snort
シンボリックリンクの作成

# cd /usr/sbin
# ln -s /usr/local/bin/snort snort
各ファイル・ディレクトリのパーミッションの設定

# cd /var/log
# mkdir snort
# chmod 700 snort
# chown -R snort:snort snort
# cd /usr/local/lib
# chown -R snort:snort snort*
# chown -R snort:snort snort_dynamic*
# chown -R snort:snort pkgconfig
# chmod -R 700 snort*
# chmod -R 700 pkgconfig
# cd /usr/local/bin
# chown snort:snort daq-modules-config
# chown snort:snort u2*
# chmod 700 daq-modules-config
# chmod 700 u2*
# cd /etc
# chown -R snort:snort snort
# chmod -R 700 snort
テストコマンドを打ってみる

# cd /usr/local/bin
# ./snort -T -i eth0 -u snort -g snort -c /etc/snort/snort.conf
以下のメッセージが表示されればOK


・(略)

Snort successfully validated the configuration!
Snort exiting
しかし

ERROR: snort.conf(253) Could not stat dynamic module path
"/usr/local/lib/snort_dynamicrules": No such file or directory.
Fatal Error, Quitting.
が表示された。
対処法

# mkdir -p /usr/local/lib/snort_dynamicrules
# chown -R snort:snort /usr/local/lib/snort_dynamicrules
# chmod -R 700 /usr/local/lib/snort_dynamicrules
chkconfigに登録

# chkconfig --add snort
手動で実行するには

# /usr/local/bin/snort -A fast -b -d -D -i eth0 -u snort -g snort -c /etc/snort/snort.conf -l /var/log/snort

DBとの連携 barnyard2のインストール

barnyard2をダウンロードとインストール


# cd /usr/local/src
# git clone []https://github.com/firnsy/barnyard2.git[]
# cd barnyard2
# ./autogen.sh
# ./configure --with-mysql --with-mysql-libraries=/usr/lib64/mysql/
# make
# make install
# cp etc/barnyard2.conf /etc/snort
# mkdir /var/log/barnyard2
# chmod 666 /var/log/barnyard2
# touch /var/log/snort/barnyard2.waldo
MySQLにDBを作成する 赤字の部分はそれぞれのパスワードを入力する

# mysql -u root -p root_password
mysql> CREATE DATABASE snort;
mysql> CREATE USER snort@localhost;
mysql> SET PASSWORD for snort@localhost=PASSWORD('snor_password');
mysql> GRANT INSERT, SELECT on root.* to snort@localhost;
mysql> GRANT CREATE, INSERT, SELECT, DELETE, UPDATE on snort.* to snort@localhost;
テーブル作成 解凍したbarnyard2のスクリプトを使って作成する

# mysql -D snort -u root -p root_password < /usr/src/barnyard2/schemas/create_mysql
上記操作でテーブルが作成されているか確認する
コンフィグレーション
27〜30行あたりに記述されているファイルが確実にあるか確認する。青字は変更した箇所

# vi /etc/snort/barnyard2.conf
25 # set the appropriate paths to the file(s) your Snort process is using.
26 #
27 config reference_file: /etc/snort/reference.config
28 config classification_file: /etc/snort/classification.config
29 config gen_file: /etc/snort/gen-msg.map
30 config sid_file: /etc/snort/sid-msg.map

※54行目あたり
#config logdir: /tmp
 ↓
config logdir: /var/log/barnyard2

※70行目あたり
#config hostname: thor
#config interface: eth0
 ↓
config hostname: localhost
config interface: eth0

※141行目あたり
#config waldo_file: /tmp/waldo
 ↓
config waldo_file: /var/log/snort/barnyard2.waldo

※最後に以下の行を追記
output database: log, mysql, user=snort password= dbname=snort host=localhost

Snortのログ出力を止める

# vi /etc/sysconfig/snort
※14〜19行目をすべてコメントにする
14 #LOGDIR=/var/log/snort
15 #ALERTMODE=fast
16 #DUMP_APP=1
17 #BINARY_LOG=1
18 #NO_PACKET_LOG=0
19 #PRINT_INTERFACE=0
動作テスト

※/etc/snort/rules/local.rulesに以下のテスト用alertを記述しておく
alert icmp any any -> any any (msg:"ICMP Testing Rule"; sid:1000001; rev:1;)

※barnyard2を起動する
# cd /usr/local/bin
# ./barnyard2 -c /etc/snort/barnyard2.conf -d /var/log/snort -f merged.log -w /var/log/snort/barnyard2.waldo

※もうひとつのターミナルウィンドウを立ち上げて当該サーバにpingコマンドを打つ。
 barnyard2を開いているターミナルにリアルタイムにalertが表示されればOK。
 nmapでポートスキャンもしてみてalertが表示さるかも確認。

barnyard2をシステムに登録する

# cp /usr/local/src/barnyard2/rpm/barnyard2 /etc/init.d/
# chmod +x /etc/init.d/barnyard2
# cp /usr/local/src/barnyard2/rpm/barnyard2.config /etc/sysconfig/barnyard2
# chkconfig --add barnyard2
以下のようなWarningを頻繁に出します。

Jul 5 05:38:55 XXXXXXXXXX barnyard2[25974]: WARNING database: [Database()] Failed transaction with current query transaction #012
Jul 5 05:38:55 XXXXXXXXXX barnyard2[25974]: WARNING database: Failed Query Position [1] Failed Query Body [INSERT INTO event (sid,cid,signature,timestamp) VALUES (1, 6735, 479, '2013-07-05 05:38:50');]


Jul 5 06:40:41 XXXXXXXXXX barnyard2[25974]: WARNING database [Database()]: End of failed transaction block
Jul 5 06:40:41 XXXXXXXXXX barnyard2[25974]: [RollbackTransaction(): Call failed, we reached the maximum number of transaction error [10]
Jul 5 06:40:41 XXXXXXXXXX barnyard2[25974]: FATAL ERROR: database Unable to rollback transaction in [Database()]
Jul 5 06:40:41 XXXXXXXXXX barnyard2[25974]: Barnyard2 exiting
いくつかWARNINGを確認してみたのですが、DBには記録されているようです。問題は一日で多いときで5回ほど落ちること。解決方法や原因を御教授いただけるとありがたいです。現在以下のようにして暫定的に対処しています。

※以下スクリプトを適当な名前をつけてcron.hourlyで監視させている
#!/bin/bash

AT_WORK=`ps ax | grep barnyard2 | sed -n '/:[0-9][0-9] barnyard2 -D -c/ p' | wc -l`

if [ ${AT_WORK} -ne 1 ]; then
service barnyard2 start > /dev/null
echo 'Restart Barnyard2!' | mail -s 'Barnyard2 failuer!' root
fi

Baseのインストール (Snortのアラートをwebで見られるようにする)


※適当なディレクトリにダウンロード
# wget []http://sourceforge.net/projects/secureideas/files/BASE/base-1.4.5/base-1.4.5.tar.gz[]
# wget []http://sourceforge.net/projects/adodb/files/adodb-php5-only/adodb-518-for-php5/adodb518a.tgz[]
# tar -xzvf base-1.4.5.tar.gz
# tar -xzvf adodb518a.tgz
# cp -r adodb5 /var/www
# mkdir /var/www/base
# cp -r base-1.4.5/* /var/www/base/
# cd /var/www/base
※base_conf.phpにリネームする
# mv base_conf.php.dist base_conf.php
# vi base_conf.php


50 $BASE_urlpath = '/base';


80 $DBlib_path = '/var/www/adodb5';


102 $alert_dbname = 'snort';
103 $alert_host = 'localhost';
104 $alert_port = '3306';
105 $alert_user = 'snort';
106 $alert_password = '実際のパスワード';
※Webサーバの設定やアクセス制限については、http://centossrv.com/apache.shtml‎http://htaccess.pasoa.com/などを参考にしてください。
/var/www/base(https://zzzz.zz/base/とか)をブラウザーでアクセスして以下の作業をする。

base_main.php を開く

The underlying database snort@localhost appears to be incomplete/invalid.” のメッセージがある

Setup page” をクリック

Create BASE AG”ボタンをクリック

メインページを開く
/var/www/baseはbasic認証をかけて特定IPのみのアクセス制限をかけてSSLでブラウズしている。
その後グラフ表示もできるようにしてみたが、ほとんど使わないのでここでは端折ります。

Snort ルールファイル自動アップデート Pulledporkのインストール

前準備…
perl-Net-SSLeay,
perl-libwww-perl,
perl-Archive-Tar
がインストールされていなかったら必ずインストール。ちなみにこの時点でインストール済みだったので私はなにもしなかった。


# cd /usr/local/src/
# wget []https://pulledpork.googlecode.com/files/pulledpork-0.6.1.tar.gz[]
# tar zxvf /usr/local/src/snort/pulledpork-0.6.1.tar.gz
# mv pulledpork-0.6.1 pulledpork ※←リネームした
# vi /usr/local/src/pulledpork/etc/pulledpork.conf


20 rule_url=[]https://www.snort.org/reg-rules/[]|snortrules-snapshot.tar.gz|
21 # get the rule docs!
22 #rule_url=[]https://www.snort.org/reg-rules/[]|opensource.gz|
23 #rule_url=[]https://rules.emergingthreats.net/[]|emerging.rules.tar.gz|open
24 # THE FOLLOWING URL is for etpro downloads, note the tarball name change!
25 # and the et oinkcode requirement!
26 #rule_url=[]https://rules.emergingthreats.net/[]|etpro.rules.tar.gz|


71 rule_path=/etc/snort/rules/snort.rules


86 local_rules=/etc/snort/rules/local.rules


89 sid_msg=/etc/snort/sid-msg.map


108 snort_path=/usr/local/bin/snort


112 config_path=/etc/snort/snort.conf


116 sostub_path=/etc/snort/rules/so_rules.rules


124 distro=RHEL-6-0


159 pid_path=/var/run/snort_eth0.pid
snort.confを修正する

# sed -i '/^include $RULE_PATH/d' /etc/snort/snort.conf
# echo "include \$RULE_PATH/snort.rules" >> /etc/snort/snort.conf
# echo "include \$RULE_PATH/local.rules" >> /etc/snort/snort.conf
# echo "include \$RULE_PATH/so_rules.rules" >> /etc/snort/snort.conf
pulledpork実行

/usr/local/src/pulledpork/pulledpork.pl -c /usr/local/src/pulledpork/etc/pulledpork.conf
※以下のようなエラーが!SSLeay.pm が見つからないらしい
Can't locate Crypt/SSLeay.pm in @INC・・・
SSLeay.pmを探す

# find `perl -e 'print "@INC"'` -name 'SSLeay.pm' -print
find: `/usr/local/lib64/perl5': そのようなファイルやディレクトリはありません
find: `/usr/local/share/perl5': そのようなファイルやディレクトリはありません
/usr/lib64/perl5/Net/SSLeay.pm
/usr/lib64/perl5/Net/SSLeay.pmにあるのでpulledpork.plファイルの冒頭の部分を修正する

# vi /usr/local/src/pulledpork/pulledpork.pl

use strict;
use warnings;
use File::Copy;
use LWP::UserAgent;
use HTTP::Request::Common;
use HTTP::Status qw (is_success);
use Crypt::SSLeay;

 ↓下のように変更

use strict;
use warnings;
BEGIN{
push(@INC, '/usr/lib64/perl5/Net');
}

use File::Copy;
use LWP::UserAgent;
use HTTP::Request::Common;
use HTTP::Status qw (is_success);
#use Crypt::SSLeay;
use Net::SSLeay;
再度実行したら以下のようなメッセージが表示されればOK。

[]http://code.google.com/p/pulledpork/[]
_____ ____
`----,\ )
`--==\\ / PulledPork v0.6.1 the Smoking Pig
crontabに登録して毎日実行

0 0 * * * root /usr/local/src/pulledpork/pulledpork.pl -c /usr/local/src/pulledpork/etc/pulledpork.conf



参考サイト


秒単位で実行させたいプログラム

検索すると…


* * * * * hoge & sleep 15; hoge
が15秒毎に実行するという記事を見ましたが、ホントウ? 30秒指定ならOKですが、これだと毎分00秒に実行したとすると、その後15秒に実行するだけで、30秒と45秒は実行されないのでは?

* * * * * hoge & sleep 15; hoge & sleep 15; hoge & sleep 15; hoge
と、するべきかも

privateやprotectedメソッドをテストするのにつまずきました

で、こんなふうにしてみた…
HogeHelperのprotectedメソッド_taiGet()をテストするとします。


public $HogeRenderer = null;
public function setUp () {
$Controller = new Controller();
$View = new View($Controller);
$this->HogeRenderer = new HogeHelper($View);
以下略
で、テストではこんなふうに

public function test_taiGet () {
$ref = new ReflectionMethod('HogeHelper', '_taiGet');
$ref->setAccessible(true);

$this->assertEqual(
'tai',
$ref->invoke($this->HogeRenderer, 'ebi'))
);
以下略

と、しているわけですが、もっとなにかスマートな方法はないでしょうかね。

それから…privateやpublicに関係なくpreg_replace_callbackを使っているメソッドを複数回実行すると一回目は成功するが二回目以後が Fatal error になるのはなぜだろう?

JSLintでボロボロの結果に…

ずいぶん前にチェックしたソースを再びチェックしたらエラー出まくりのボロボロの結果になってしまった。どうやらオプションのチェック項目が増えているような?以前のソースをローカルに落としていなかったので何が増えているのかよくわからない。

で、古いソースを修正したり追記した場合、とりあえず以前のチェックパターンというか差しさわり無い程度にチェックしたいとき、だいたいこんな感じなのかなというのが以下のパターン。"古い"とか"以前"というのがワタクシ的な定義ですのでご参考までに。

Tolerate dangling _ in identifiers:プライベート変数or関数のために先頭にアンダースコアを入れているソースではエラー表示される。プライベート用の名前空間をつくってそこに放り込んでおくのがいいんでしょうね。my.member = value; みたいに。

Tolerate misordered definitions:document やwindowなどソース外のオブジェクトを記述していたりするとエラー表示される。Predefinedのテキストボックスにカンマで区切って記述すればいいので、できれば無効にしないほうが良いですね。

Tolerate missing 'use strict' pragma:新しくコーディングするときはstrictモードで記述すべきでしょう。ただし'use strict;'を記述するとこのチェックを無効にしてもstrictモードとしてちゃんとチェックはするようだ。

Tolerate many var statements per function:あちこちにvar var 書いてあると、Problem at line 254 character 23: Combine this with the previous 'var' statement. のようなメッセージ(varの宣言を一か所にまとめろ)が出まくることになる。あわてて古いソースをやみくもに修正するとかえってバグの元になるので要注意。

Tolerate messy white space:タブとスペースの混在やインデントのミスを(口やかましくww)教えてくれます。現状で見やすいんだからいいじゃん…で済む場合は無効にしておきましょ。

JREが原因だったとは…

以前EclipseにERMasterをインストールしたとき、テストデータ作成画面のコンテキストメニューやらなにやらが、あちこちが字化けしてしまって使い物にならなかった。プルダウンメニューなんかも不正な表示をしてたのでCentOSの環境では使用をあきらめERMasterだけWindowsで使っていた。

で、今度はドキュメント作成のためのXMLmindをインストールしたら、入力する日本語が字化けする。文字が四角で表示されてERMasterと症状が似ているので、検索したらJRE(Java実行環境)の日本語フォントの設定が悪かったみたい。いずれのソフトも日本語化しないで使用してたので全く見当もつかなかった。

/usr/lib/jvm/jre/lib/にはfontconfig.ほにゃららがたくさんある。その中で一番基本的なネーミングのfontconfig.properties.srcファイルを開く。いろいろごにょごにょ記述してある。例えば dialog.plain.japanese-x0208=Sazanami Gothic のように日本語向け設定のような箇所にSazanami Gothicがある。で、ずっと下の方を見ると filename.Sazanami_Gothic=/usr/share/fonts/japanese/TrueType/sazanami-gothic.ttf のパスの指定が…。

CentOS6自体にsazanamiフォントが無いようだし、/usr/share/fonts/をみてもどこに日本語フォントがあるのかわからない。なのでIPAフォントをダウンロードした。

/usr/share/fonts/にjapanese/TrueType/ ディレクトリを作ってIPAフォントのipag.ttfとipam.ttfをコピーした。JREのfontconfigファイルはいちいち全部修正するのが面倒くさいのでfilenameを指定しているsazanami-gothicやsazanami-minchoの部分をそれぞれipag.ttf、ipam.ttfに置き換えた。下記


#filename.Sazanami_Gothic=/usr/share/fonts/japanese/TrueType/sazanami-gothic.ttf 
filename.Sazanami_Gothic=/usr/share/fonts/japanese/TrueType/ipag.ttf
#filename.Sazanami_Mincho=/usr/share/fonts/japanese/TrueType/sazanami-mincho.ttf
filename.Sazanami_Mincho=/usr/share/fonts/japanese/TrueType/ipam.ttf
.srcの拡張子を削除してfontconfig.propertiesにして、他のfontconfigファイルはすべて削除(するのはちょっと怖いのでhomeディレクトリに移動しておいた)する。これでばっちりXMLmindで日本語が入力できるようになりました。めでたし!ついでにERMasterもちゃんと使えるようになった。

ちなみにJREのlibにfonts/fallbackディレクトリを作って日本語フォントのシンボリックリンクを置くという方法をあちこちで見たのですがうまくいきませんでした。

参考サイト:http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/intl/fontconfig.html