start

BlogTNGに迷惑トラックバック除けを仕込む

昨日CAPTCHAの日本語化改造を行ったものの、未だにスパムが来る。平仮名も解析する高性能botなのか?と少し絶望しつつ、改めてスパム履歴を見ていたところ大半がトラックバックだった。captchaの意味なし。/(^o^)\ナンテコッタイ。

そもそもBlogTNGにトラックバックを受け取る機能付いてんの?って話だが(エントリーのどこにもトラックバックアドレスが書かれてないし)、生成されたHTMLを見てみると、RSSの中にtrackback:pingとして埋め込まれていた。なるほどなー、糞スパマーどもはRSSで爆撃対象を効率的に集めながらスパム行為をしてるわけか。少し感心したが、スパマーは氏ね。

当該部分の生成はblogtng/action/linkback.phpで行われているので、てきとーにスパム除け仕様にしといた。

今度こそ・・・今度こそ収まるはずだ・・・!

日本語captcha作ったった

「ギャラクシーS3のカスタムケースあるよ」(英語)というスパムコメントが死ぬほどウザい。一晩で500件も投稿すんな!クソチョンのガラクターなんて持ってねーし、買う気もねーよksg。iPhone関連のスパムはなく、なんでガラクターだけなんだよ。ステマしてんじゃねーよトンスル民族!!

もうマジでげきオコスティックファイナリアリティぷんぷんドリーム状態なので、怒りのままにcaptchaプラグインのひらがな対応化改造を行った。外国人涙目だろうが、こんなクソみたいなサイトを見てる奇特な人は居ないだろうから気にしない。これでbotを誤魔化せるといいんだが…。

折角なのでパッチを公開しておく。

  • CAPTCHA plugin 2013/04/29 15:50版以降
  • Unicode対応の日本語True Typeフォント(ライセンス的に画像化してもいいもの)
  • ↓のパッチ
captcha_ja.patch
--- a/helper.php	2013-04-29 06:50:38.000000000 +0900
+++ b/helper.php	2013-05-05 19:55:44.000000000 +0900
@@ -88,7 +88,7 @@
                 }
                 break;
         }
-        $out .= ' <input type="text" size="5" maxlength="5" name="'.$this->field_in.'" class="edit" /> ';
+        $out .= ' <input type="text" size="10" maxlength="10" name="'.$this->field_in.'" class="edit" /> ';
 
         // add honeypot field
         $out .= '<label class="no">Please keep this field empty: <input type="text" name="'.$this->field_hp.'" /></label>';
@@ -150,11 +150,18 @@
         $numbers = md5($rand * $fixed); // combine both values
 
         // now create the letters
+/*
         $code = '';
         for($i=0;$i<10;$i+=2){
             $code .= chr(floor(hexdec($numbers[$i].$numbers[$i+1])/10) + 65);
         }
-
+*/
+        $strTable = 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゐゆゑよらりるれろわをん';
+        $strLength = mb_strlen($strTable);
+        $code = '';
+        for ($i=0;$i<10;$i+=2){
+            $code .= mb_substr($strTable, hexdec($numbers[$i].$numbers[$i+1])%$strLength, 1);
+        }
         return $code;
     }
 
@@ -203,7 +210,7 @@
         }
 
         // draw the letters
-        for ($i = 0; $i < strlen($text); $i++){
+        for ($i = 0; $i < mb_strlen($text); $i++){
             $font  = $fonts[array_rand($fonts)];
             $color = imagecolorallocate($img, rand(0, 100), rand(0, 100), rand(0, 100));
             $size  = rand(floor($h/1.8),floor($h*0.7));
@@ -213,7 +220,7 @@
             $cheight = $size + ($size*0.5);
             $y = floor($h / 2 + $cheight / 3.8);
 
-            imagettftext($img, $size, $angle, $x, $y, $color, $font, $text[$i]);
+            imagettftext($img, $size, $angle, $x, $y, $color, $font, mb_substr($text, $i, 1));
         }
 
         header("Content-type: image/png");
  1. CAPTCHAプラグインをインストール
  2. CAPTCHAの種類を「Image」にする
  3. lib/plugins/captcha/fonts に最初から入っているフォントを使えない状態にする(拡張子を .ttf_ にするなど)
    • ↑にある.ttfをランダムに選んで認証画像を作るので、非日本語フォントがあると正しく画像が生成されない。
  4. lib/plugins/captcha/fonts に日本語フォントを置く
    • ライセンスに注意。IPAフォント(IPAフォントライセンスv1.0準拠)あたりなら問題ないと思われる。
  5. 拙作パッチを当てる
  • 「Image」以外では動作しません。
  • 文字コードはUTF-8しか想定してないので、ブラウザによっては認証が通らない事があるかも?
  • $strTable を書き換える事で、認証に使う文字を変えられる。小難しい漢字や似た漢字(「博」と「愽」とか)を入れれば更に効果的かも知れない(笑)

Portsにnetatalk 3.0.3がキタ━━━(゚∀゚)━━━ !!!!!

Portsのnetatalk3が3.0.3に更新された。

普通に更新してもいいのだが、折角なので[netatalk-ja:0155] Re: 3.0.2でPhotoshop CS5で濁音のファイルがセーブできないのパッチを適用してみる。

この問題を簡単に解説すると、netatalkがリソースフォークを処理する際にファイル名の文字コード変換(Unicode正規化含む)が正常に働かないため、リソースフォークを持ちファイル名に非ASCII文字を含むファイルが保存できないというもの。最近はリソースフォークを持つファイルも減ったようなので(かくいう私はPantherの後半の頃からMacを使い出したのでリソースフォーク全盛の頃を知らなかったりするのだが)、殆どのnetatalk環境では問題が起きないと思われる。ファイルシステムの文字コード絡みの問題なので、ZFSでUnicode正規化を強制してるような環境でも問題は起きない(まさにうちの環境w)。

尚、パッチはTrunk開発ラインに取り込まれているので、3.0.4リリースの暁には直る模様。

果てしなく行儀が悪いけど、お手軽にportsにパッチする形でインストールする。

cd /usr/ports/net/netatalk3
sudo make patch
cd work/netatalk-3.0.3
sudo curl -O http://www003.upp.so-net.ne.jp/hat/files/git-bug511-forkname.patch.gz
sudo gzip -d git-bug511-forkname.patch.gz
sudo patch -p1 < git-bug511-forkname.patch
cd ../../
sudo make
sudo make install

パッチをあてると3.0.4devとしてインストールされるので確認。

$ afpd -v
afpd 3.0.4dev - Apple Filing Protocol (AFP) daemon of Netatalk
 
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version. Please see the file COPYING for further information and details.
 
afpd has been compiled with support for these features:
...

よし、OKだ。

ZFS mirrorのプールがデグレードしていたでござる

サーバの共有フォルダに繋がらなくなってしまった。サーバ自体は見えておりpingも通るのだが、いざ繋ごうとするとタイムアウト。その時は家のネットワークを色々弄くっていたので、それが原因かな?と気にも留めなかった。

翌日になっても繋がらなかったので、原因を調べるべくsshしたが一向に応答が帰ってこない。pingは通るのに。コンソールから直接ログインを試みるも、ユーザー名入力後に応答が帰ってこずに撃沈。これはヤバい雰囲気。仕方なく電源リセット。

幸い、問題なく起動しsshも繋がったので調査開始。

まずは /var/log/messages を見てみる。

...
Apr 19 20:24:31 Freyja kernel: mpt0: request 0xffffff800082f3a0:16151 timed out for ccb 0xfffffe0007da2800 (req->ccb 0xfffffe0007da2800)
Apr 19 20:25:16 Freyja kernel: mpt0: attempting to abort req 0xffffff800082f3a0:16151 function 0
Apr 19 20:25:16 Freyja kernel: mpt0: mpt_wait_req(1) timed out
Apr 19 20:25:16 Freyja kernel: mpt0: mpt_recover_commands: abort timed-out. Resetting controller
Apr 19 20:25:16 Freyja kernel: mpt0: mpt_cam_event: 0x80
Apr 19 20:25:16 Freyja kernel: mpt0: mpt_cam_event: 0x80
Apr 19 20:25:16 Freyja kernel: mpt0: completing timedout/aborted req 0xffffff800082f3a0:16151
Apr 19 20:31:14 Freyja kernel: mpt0: request 0xffffff800082c460:17593 timed out for ccb 0xfffffe0007da2800 (req->ccb 0xfffffe0007da2800)
Apr 19 20:31:14 Freyja kernel: mpt0: attempting to abort req 0xffffff800082c460:17593 function 0
Apr 19 20:31:18 Freyja kernel: mpt0: completing timedout/aborted req 0xffffff800082c460:17593
Apr 19 20:31:18 Freyja kernel: mpt0: abort of req 0xffffff800082c460:0 completed
Apr 19 20:32:42 Freyja kernel: mpt0: request 0xffffff8000833720:17797 timed out for ccb 0xfffffe0007da2800 (req->ccb 0xfffffe0007da2800)
Apr 19 20:32:45 Freyja kernel: mpt0: attempting to abort req 0xffffff8000833720:17797 function 0
Apr 19 20:32:45 Freyja kernel: mpt0: completing timedout/aborted req 0xffffff8000833720:17797
Apr 19 20:32:45 Freyja kernel: mpt0: abort of req 0xffffff8000833720:0 completed
...

なんかヤバげなログががが。mptってことはHDDが逝っちゃった系・・・?

次にZFSプールの状態を見てみる。

$ zpool status
  pool: zroot
 state: DEGRADED
status: One or more devices could not be opened.  Sufficient replicas exist for
	the pool to continue functioning in a degraded state.
action: Attach the missing device and online it using 'zpool online'.
   see: http://www.sun.com/msg/ZFS-8000-2Q
 scan: scrub repaired 0 in 3h41m with 0 errors on Fri Nov  2 00:13:33 2012
config:

	NAME                      STATE     READ WRITE CKSUM
	zroot                     DEGRADED     0     0     0
	  mirror-0                DEGRADED     0     0     0
	    12202321002681728230  UNAVAIL      0     0     0  was /dev/da0p3
	    da0p3                 ONLINE       0     0     0

errors: No known data errors

オフフ、ミラーの片割れがUNAVAILになっとる。本来あるべきada7p3が行方不明。

camcontrol devlistで見てもada7が出てこないので本格的にお亡くなりになった?と考えつつ、最後の望みをかけてマシン開腹&ケーブルチェック。なんか微妙にSATAケーブルが緩かった気がする。いざ起動アーンドzpool status!!

  pool: zroot
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
	continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scan: resilver in progress since Sun Apr 21 11:03:14 2013
    1.01G scanned out of 557G at 9.96M/s, 15h52m to go
    1.01G resilvered, 0.18% done
config:

	NAME        STATE     READ WRITE CKSUM
	zroot       ONLINE       0     0     0
	  mirror-0  ONLINE       0     0     0
	    ada7p3  ONLINE       0     0     3  (resilvering)
	    da0p3   ONLINE       0     0     0

ktkr!!

とりあえず、ハードリセットもしてしまったことだし、他のプールも含めてscrub。問題のプールは560GBで4時間ほど掛かった。

errors: No known data errors

  pool: zroot
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
	attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
	using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scan: scrub repaired 384K in 4h8m with 0 errors on Sun Apr 21 15:38:59 2013
config:

	NAME        STATE     READ WRITE CKSUM
	zroot       ONLINE       0     0     0
	  mirror-0  ONLINE       0     0     0
	    ada7p3  ONLINE       0     0     6
	    da0p3   ONLINE       0     0     0

errors: No known data errors

よしよし、無事修復出来たようなのでzpool clearでエラーカウントをクリアして完了っと。

しかしSATAケーブルが緩むなんて事あるんだねぇ。ラッチ付きじゃないとあかんな。

Disk Arbitration Frameworkでディスクのマウントを抑制する

物理HDDをVirtualBoxのVMに割り当てて使用中、Mac OSからそのHDDをマウントされると非常に不味いので、マウントを抑制するコマンドを作ってみた。

引数にBSDデバイス名(/dev/disk5とか)を渡してコマンドを実行すると、Mac OS側からのマウントをブロックする。デバイス名は前方一致で検索しているので、/dev/disk5と書けばdisk5全体が、/dev/disk5s1と書けばdisk5のスライス1がブロック対象となる。終了はCtrl-Cで。

どこか処理が不味いようで、何かの拍子にコマンドを終了してもFinderからはマウント不能?と認識されてしまうことがある(実際はマウントされているのでopenコマンドを使えば開ける)。こうなると再起動するしかなくなる…。AS ISでおながいします。

blockMount.c
// -*- coding: utf-8-unix -*-
// ---------------------------------------------------------
//  Block Mount Utility
//  Copyright (c) 2013 Decomo
// ---------------------------------------------------------
//  License:
//      2-clause BSD license
//  Reference:
//      https://github.com/nanoant/mountblockd
//      http://stackoverflow.com/questions/3720503/how-can-i-prevent-ejection-of-a-disk-during-an-operation-on-mac-os-x
//      http://superuser.com/questions/336455/mac-lion-fstab-is-deprecated-so-what-replaces-it-to-prevent-a-partition-from-m
//      http://www.geekpage.jp/blog/?id=2011/10/4/3
//      http://developer.apple.com/library/mac/#documentation/Darwin/Reference/DiscArbitrationFramework/
//  Compile:
//      cc BlockMount.c -g -o BlockMount -framework CoreFoundation -framework DiskArbitration
// ---------------------------------------------------------
 
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
#include <stdio.h>
#include <stdlib.h>
 
const char **g_blockDeviceList = NULL;
int g_blockDeviceListCount = 0;
int g_verbose = 0;
int g_run = 1;
 
DADissenterRef diskWillMount(DADiskRef disk, void *context)
{
    const char *devName = DADiskGetBSDName(disk);
    DADissenterRef dissenter = NULL;
 
    if (devName)
    {
        int block=0;
        for (int i=0; i<g_blockDeviceListCount; i++)
        {
            if (strstr(devName, g_blockDeviceList[i]))
                block=1;
        }
        if (block)
        {
            if (g_verbose)
                fprintf(stderr, "BLOCKED mount `%s'\n", devName);
            dissenter = DADissenterCreate(kCFAllocatorDefault, kDAReturnNotPermitted, NULL);
        }
    }
 
    return dissenter;
}
 
void signalHandler(int sig)
{
    switch (sig) {
    case SIGHUP:
        if (g_verbose)
            fprintf(stderr, "received SIGHUP, terminating...\n");
        CFRunLoopStop(CFRunLoopGetCurrent());
        g_run=0;
        break;
    case SIGTERM:
        if (g_verbose)
            fprintf(stderr, "received SIGTERM, terminating...\n");
        CFRunLoopStop(CFRunLoopGetCurrent());
        g_run=0;
        break;
    case SIGINT:
        if (g_verbose)
            fprintf(stderr, "received SIGINT, terminating...\n");
        CFRunLoopStop(CFRunLoopGetCurrent());
        g_run=0;
        break;
    case SIGQUIT:
        if (g_verbose)
            fprintf(stderr, "received SIGQUIT, terminating...\n");
        CFRunLoopStop(CFRunLoopGetCurrent());
        g_run=0;
        break;
    default:
        fprintf(stderr, "unhandled signal (%d) %s\n", sig, strsignal(sig));
        break;
    }
}
 
int main(int argc, const char *argv[])
{
    int usage=1;
    if (argc >= 2)
    {
        usage=0;
        if (strcmp(argv[1], "-v") == 0)
        {
            g_verbose=1;
            g_blockDeviceList = &argv[2];
            g_blockDeviceListCount = argc-2;
            if (argc == 2)
            {
                usage=1;
            }
        }
        else
        {
            g_blockDeviceList = &argv[1];
            g_blockDeviceListCount = argc-1;
        }
    }
 
    if (usage)
    {
        fprintf(stderr, "usage: %s [-v] deviceName1 [deviceName2] [deviceName3] [...] \n", argv[0]);
        return EXIT_FAILURE;
    }
 
    fprintf(stderr, "blocking mount device(s) : ");
    for (int i=0; i<g_blockDeviceListCount; i++)
    {
        fprintf(stderr, "%s ", g_blockDeviceList[i]);
    }
    fprintf(stderr, "\n");
 
    signal(SIGHUP,  signalHandler);
    signal(SIGTERM, signalHandler);
    signal(SIGINT,  signalHandler);
    signal(SIGQUIT, signalHandler);
 
    DAApprovalSessionRef session = DAApprovalSessionCreate(kCFAllocatorDefault);
    if (!session)
    {
        fprintf(stderr, "failed to create DAApprovalSession.\n");
        return EXIT_FAILURE;
    }
    else
    {
        DARegisterDiskMountApprovalCallback(session, NULL, diskWillMount, NULL);
        DAApprovalSessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
 
        while (g_run)
        {
            CFRunLoopRun();
        }
 
        DAApprovalSessionUnscheduleFromRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
        DAUnregisterApprovalCallback(session, diskWillMount, NULL);
        CFRelease(session);
    }
 
    return 0;
}

とまぁ、とりあえず作ってはみたものの、結局仮想マシンはVMware Fusionを常用してるので出番がないっていう。何だかんだでVirtualBoxは不安定なんだよねぇ。8 CPU以上使えるのは魅力的なんだけど。

  • start.txt
  • 最終更新: 2022-07-27 15:26
  • by Decomo