さくらのVPSへの不審なアクセス

lastbをやると、膨大な数の不審なアクセスがあることがわかる。

ほぼすべて、ユーザ名を変えつつssh接続を試みているものだ。

そしてちょっとした「ビッグデータ」なので、件数を数えてみた。

10270 176.227.XX.XX GB
4638 211.144.XX.XX CN
4505 116.255.XX.XX CN
3566 49.212.XX.XX JP
3241 178.79.XX.XX GB
1728 58.241.XX.XX CN
1572 217.12.XX.XX RU
1427 61.130.XX.XX CN
792 111.74.XX.XX CN
466 112.65.XX.XX CN
(以下略)


最多だったアドレスはイギリスからであった。中国からが多い。ちなみに国名はアドレスをwhoisで引いて調べた。アドレスは晒してもいいのだが一応一部伏せた。こういうアクセスは、スクリプトが流布していて、興味本位かダメ元でやってるだけではないかと思う。プロバイダに文句を言ってもキリがないしな・・・。

使われているユーザ名も数えてみた。

root,35928
test,886
nagios,800
admin,632
oracle,572
user,446
postgres,392
webmaste,322
web,320
ftpuser,308
backup,294
www,260
tomcat,234
guest,232
mysql,222
support,178
testuser,170
user1,148
hadoop,142
user2,128
temp,126
teamspea,124
mythtv,112
download,106
www-data,104
ftpguest,104
info,102
prueba,102
ftptest,100
teste,92
webuser,90
mailman,84
cacti,82
gast,76
suporte,72
office,70
bin,70
student,68
mailtest,64
gnats,62
koha,62
squid,56
alex,54
minecraf,52
firefly,52
news,52
informix,52
ftp,50
david,50
postmast,50
kiosk,48
(以下略)


ひとつ、使われている可能性が非常に高い(実際私が使っている)ユーザ名を試していないことに気づいた。そんなものすら試していないことからも、この手のアクセスが「本気」でないことが想像できる。

別に痛くもかゆくもないし・・・と思っていたが、時々sshがすごく重くなるのはこのせいかと思って、sshdのポート番号を変えた。

使われているユーザ名を数えたスクリプト。

最初にlastbの結果をファイルに書いておいてそれを読ませる。

while(<>){
    ($name) = split;
    push @list, $name;
}

%hash;

for (@list){
    if(exists $hash{$_}){
        $hash{$_}++;
    }else{
        $hash{$_}=1;
    }
}

foreach my $name (sort { $hash{$b} <=> $hash{$a} } keys %hash){
    print "$name,$hash{$name}\n";
}


キモはハッシュをキーでなくデータ(この場合ユーザ名)でソートするところだ。

「キーがハッシュに存在すれば値を加算、なければ追加」というところが、もっと簡単にできそうなのだが、こうするしかないかな?

for (@list){
    $hash{$_}++;
}


これでいいみたいだ。わざわざ「なければ」とかしなくても。




pukiwikiが動かない

pukiwikiを入れた。

前回VPSを借りたときにもインストールしたはず。

が、動かない。

インストールといってもtarで展開するだけだ。

ブラウザで、「サーバーエラー」となり、下の方に「500(Internal Server Error)」と書いてある。しかし、/var/log/httpd/error_log には何も出ない。

フォルダをcgi-binの下に移動したりしてみたがダメだ。

違うPHPのファイルを index.phpという名前にして置いてみると動く。

なんだろう?PHPのバージョンだろうか?

index.phpの、エラーレポートのレベルのようなものを指定している箇所を E_ALLに変更してみると、/var/log/httpd/error_log が出た。

// Error reporting
//error_reporting(0); // Nothing
//error_reporting(E_ERROR | E_PARSE); // Avoid E_WARNING, E_NOTICE, etc
error_reporting(E_ALL); // Debug purpose


[error] [client xx.xx.xx.xx] PHP Fatal error:  Cannot redeclare hex2bin() in /var/www/html/wiki/lib/func.php on line 317


調べるとやっぱりバージョンのせいのようだ。要は、phpが新しすぎるのだ。

回避方法があるようだが、メンドクサそうなので、後にする。


postfix

送信メールサーバ(MTAと呼ぶのか)はsendmailではなくpostfixを使った。

しばらく前にインストールしたのだがクライアント(Windows7のLiveメール)から送信ができなかった。

smtp      inet  n       -       n       -       -       smtpd
submission inet n       -       n       -       -       smtpd
-o smtpd_tls_security_level=may
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination
-o milter_macro_daemon_name=ORIGINATING


さっきできるようになったのだが、直したところは /etc/postfix/master.cf の、



  • o smtpd_tls_security_level=encrypt を mayにしてpoxtfix reloadしただけだ。

ここがencryptになっていると暗号化を強制するのかな?

encryptにしてあると、クライアントからサーバにアクセスしたとたんに切断され、

STARTTLSが必要とかなんとかいうエラーになる。

クライアント側でTLSを使うようにしてもよいのだろうがよくわからない。

あと、submission... という行があるが、これがあるとサブミッションポートというものが有効になる。

サブミッションポートというのは「587番でも待つ」という仕組みらしい。単に、SMTPのポート番号を変える、というものではないようなのだが何が違うのかよくわからない。

クライアント側の設定は、送信メールサーバのポート番号を587にし、「送信メールサーバで認証が必要」の設定にする。




つづいて、pythonを最新にする。

今までのは2.6.6だったが、2.7.3にする。

ソースを持ってきてコンパイルする。

$ sudo yum install zlib zlib-devel tk-devel tcl-devel sqlite-devel ncurses-devel gdbm-devel readline-devel bzip2-devel db4-devel


$ wget http://python.org/ftp/python/2.7.3/Python-2.7.3.tgz
$ tar zxvf Python-2.7.3.tgz


$ cd Python-2.7.3
$ ./configure --with-threads --enable-shared
$ make
$ sudo make install


enabled-sharedオプションは、mod_wsgiを使用する場合に必要だとのこと。

mod_wsgiはapacheで動かすときに必要とのことなのでつけておく。

[hoge]# python --version
python: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory


となるが、シンボリックリンクを張ればOK.

[hoge]# ln -s /usr/local/lib/libpython2.7.so.1.0 /lib64/
[hoge]# python --version
Python 2.7.3


つづいて、sphinxのインストール

wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py


easy_install sphinx


とやると、ダウンロードしてインストールしてくれる。

MySQL

yum --enablerepo=remi install mysql mysql-server mysql-devel mysql-libs


remiを指定しないとエラーになった。




phpのcgi

OSはデフォルトのCentOS6

cgiはperlで書いている。

phpでも何か動かせるようにしようとしたのだが、

phpのスクリプトを動かすと、htmlタグがそのまま表示されてしまう。

apacheのhttpd.confで、

AddType application/x-httpd-php .php

を書くと、ファイルがダウンロードされる。

コメントにすると、実行されるがhtmlタグがそのまま表示される。

WEBをさがしてみたが同じ状況の人がいない・・・。

「ソースが表示されてしまう」

「ダウンロードしてしまう」

という人はいる。

httpd.confの設定がどうこう、という情報はあるのだが、さくらのVPSでうまくいっている人は特に変更していない。

が、phpのバージョンが違う。

一応、あわせてみるか・・・。

「remiリポジトリ」を登録する必要があるとのことなので、


rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm


その後、以下を実行。


yum install php-mbstring --enablerepo=remi
yum install php-gd --enablerepo=remi
yum install php-pear --enablerepo=remi
yum install php-mcrypt --enablerepo=remi
yum install php-mysql --enablerepo=remi
yum install php-devel --enablerepo=remi


バージョンは


[hoge]# php -v
PHP 5.4.10 (cli) (built: Dec 19 2012 11:45:14)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies


動いた・・・

httpd.confのAddHandler, AddType applicationとかはデフォルトに戻した。

バージョンが違うというより、その後に入れたモジュールが入ったせいじゃないかな・・・

くわしくはわからん。

あと、php.iniのtimezoneの設定を変更


[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone ="Asia/Tokyo"


その下に、コメントアウトされているがlatitudeとかlongitudeとかいう設定があるのだが、なんだろう?

とりあえず無視。




ログのパース

今まではスペースでsplitして、何番目が何で、などとやっていたが、「プログラミングPerl」をざっと読んで、 いろいろ新しいことを覚えたのでそれを生かして改善してみた。
my $logfilename = './access_log';
open my $logfh,"<$logfilename" or die $!;

while(<$logfh>){

    my @dataname = qw/client_address identifier user_name time request last_status sent_bytes referer user_agent/;
    my @logdata = $_ =~ /(.*) (.*) (.*) \[(.*)\] "(.*)" (\d+) (\d+) "(.*)" "(.*)"/;
    my %logdata;

    my $i=0;
    for (@logdata){
        $logdata{$dataname[$i]} = $_;
        $i++;
    }


    foreach my $key(keys %logdata){
        print "$key : $logdata{$key}";
    }
}
close($logfh);
これはcgiのソースの一部である。 キモはパースした内容をハッシュに格納しているところだ。 今までは配列(リスト)に格納して欲しい内容の位置にアクセスしていた。 それを、いったんデータの名前だけをリストで定義し、それをキーとしてパースした結果をハッシュに格納した。 こうすれば、欲しいデータを名前で探せる。 foreachするときに、配列のインデックスが知りたかったのだがわからなかった。 「$.」ではなかった。 なのでインデックスを変数としてインクリメントした。 ここはダサい。 apacheのログパースをするモジュールなんてのもあるが、これくらいは自分でやりたい。 正規表現も、検索すればちゃんとしたものが見つかるが、これくらいは自分で書きたい。

 1.まずフォーマットを書く。
.* .* [.*]

2.取り出したいところをカッコで囲む
(.*) (.*) [(.*)]

3.エスケープを必要なところに入れる。
(.*) (.*) \[(.*)\]

4.動かして、うまくいかなかったら直す。

 「プログラミングPerl」は、Perlの聖典であるかのように、かつ、難しいと言われているが、夕べなんとなく開いて読んでいたらおもしろくて、それほど難解なこともなく、すーっと読んでしまった。

関数やライブラリモジュールの一覧解説があるので分量が多いが、それを除けばそれほどでもない。 私のもっているのは古くて、2nd Edition、1997年発行のものである。

 「初めてのPerl」「続・初めてのPerl」ももっていてだいたい読んだが、「プログラミングPerl」も早いうちに読むべきだと思う。 文中に紹介されているサンプルを知っているといないとでも大違いだ。

私はPerlを書いていてゴチャゴチャしてくると、「こんな難しくなるはずはない」と、それらのサンプルを思い出しながら、思う。

Net::TwitterをNet::Twitter::Liteに変える

わたしは自分のサイトにサーチエンジン経由でアクセスがあったときにそのキーワードをtweetさせている。

今日そこをいじって気づいたのだが、tweetさせると数十秒程度時間がかかっている。

tweetするまでではなく、tweetした後に時間がかかっている(と見えたが勘違いかもしれない)。

tweet自体はちゃんとできている。

原因はわからないが、Net::Twitter::Liteに変えたら治った。

Net::Twitterはボットでも使っていたがしばらく動かしていると死んでしまうのでLiteに変えていた。

やっぱりなんかおかしい・・・。




MeCab

さくらのVPSにmecabをインストールする。

本体と辞書をインストールする。

辞書はデフォルトでeucなので、configureのオプションでutf8にする。

MeCab: Yet Another Part-of-Speech and Morphological Analyzer


wget http://mecab.googlecode.com/files/mecab-0.994.tar.gz
tar xvzf mecab-0.994.tar.gz
cd mecab-0.994
./configure
make
make check
make install

wget http://mecab.googlecode.com/files/mecab-ipadic-2.7.0-20070801.tar.gz
tar xvzf mecab-ipadic-2.7.0-20070801.tar.gz
cd mecab-ipadic-2.7.0-20070801
./configure --with-charset=utf-8
make
make install
mecab


起動してみる。


[hoge]# mecab
母は歯は丈夫だ
母 名詞,一般,*,*,*,*,母,ハハ,ハハ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
歯 名詞,一般,*,*,*,*,歯,ハ,ハ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
丈夫 名詞,形容動詞語幹,*,*,*,*,丈夫,ジョウブ,ジョーブ
だ 助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ
EOS
^C


さて、何をしたらおもしろいかな?

・・・と、スクリプトで使うにはそのスクリプトの「バインディング」というものが必要なので、それもインストールする。


wget http://mecab.googlecode.com/files/mecab-perl-0.994.tar.gz
tar zxvf mecab-perl-0.994.tar.gz


READMEに書いてあるが、以下を実行。


perl Makefile.PL
make
su
make install


これで、use MeCab を書けば、perlで使えるようになる。

前回使ったときは辞書がeucだったのでencode/decodeが必要だったが、今度はutf8にしたのでそのままいける。

・・・さて、何をしようか。




話は変わるが、perlで日付を取得したいときに、どうやるんだっけと調べると以下のような方法が見つかる。


@youbi = ('日', '月', '火', '水', '木', '金', '土');
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$mon += 1;
print "$year年$mon月$mday日($youbi[$wday]) $hour時$min分$sec秒\n";


日付の用途はいろいろで、これならフォーマットや足し引きなども万能かもしれないが、メンドクサイ。コピペするにしても、なんかめんどくさすぎる。

単に表示するだけなら、


print scalar(localtime())."\n";


または


my $tmp = localtime();
print $tmp."\n";


結果は以下のようになる。

centosで試した。プラットフォームによって変わるのかな?


Fri Dec 21 23:26:48 2012


今日は何曜日か?を知りたいときは、上にあげたようにすればいいが、わざわざ変数をいくつも並べるのは面倒だから、


@datedata = localtime();


として、曜日であれば配列の7番目 $datedata[6] を見ればよい。

日付処理に関するモジュールがいろいろあるようだが、何でもかんでもすぐモジュールを使うのもアレだし。

perlの配列を添え字をつけて参照するときは、@array[1] ではなく、 $array[1] とするんだね。

@がつくと、配列全体を指すのか。一個一個の配列をさすときは変数扱いで $となるのか。

私はperlの配列を添え字を使って特定の変数を取り出すことはあまりしない。

たいていは丸ごとあるいはpushでどかどか突っ込んで、foreachで吐き出しながら正規表現で引っ掛けて何かする、という風に使う。




2ちゃんねるでスクレイピングが失敗する

さくらのVPSサーバから、あるサイトにアクセスし、そのWEBサイトの情報の一部を取り出すという事をしている。いわゆる「スクレイピング」である。 

最初はperlで、LWP::Useragentなどを使って、あるサイトの情報を取り、あとは正規表現などを使って試行錯誤しつつ欲しい情報のみを取り出した。 特に難しいことはない。

ところが、同じ事を2ちゃんねるでやってみたら、うまくいかない。やろうとしたのは、ニュース速報の上位のスレッドタイトルを取得することだった。 2ちゃんねるは掲示板のメニューがあってそこに各掲示板のURLが記載されている。そしてその掲示板のURLはかなり頻繁に変更されるので、そのときアクセスできているURLに固定でアクセスせずに、メニューからURLを取得しなければならない。 その、メニューからURLを取得することはできたのだが、そこから取得したURLへアクセスすると、どうしてもHTMLの内容が取得できないのだ。

まずは、「302 Found」というエラーになる。これはリダイレクトされたときに出るもののようで、あるところで

push @{ $ua->requests_redirectable }, 'POST';
をやればいいという情報を見つけたのでやってみたら、今度は「ボボンハウス」のページが表示されてしまう。

同じperlスクリプトをローカルPCで動かしても同じ状況になる。 もちろん、ブラウザやギコナビなどでは問題なくアクセスできている。 昨日はここまでやって、あきらめて寝た。 

そして今日、perlのスクリプトでアクセスしたときと、ブラウザでアクセスしたときのパケットをwiresharkでキャプチャして比較してみた。

すると、GETしているときに、・・・・ と、ここまで書いてuseragentが違うことに気づいた。 perlで書いたものは何も設定しておらず、lwpの初期値が入っている。 これを'Mozilla'に変えたら・・・いけた。

昨日、変えてダメだったような記憶があったんだけどな・・・ ま、いいや。 これだけでいけるようになるということは、2ちゃんねるの「スクリプトキディ」除けかな。

今日はWEBでphpをつかったスクレイピング例を見つけてそれがうまく動いたのでそれをいじっていた。

しかし今度はphpの動作で不可解なところがでてきた。 まず、phpをcgiとして動かすために必要な設定がなんなのか。 いろいろと情報があるのだが、皆条件付でスパっと「ここをこうする!」という情報がない。

これも試行錯誤で試して、なんとかうごいた。 前回はこんなに苦労した記憶はないのに・・・。 さらに、いちおう動いたのだが、出力する内容が全部そのまま出てしまう。 htmlのリンクとかを書いても、そのまま表示されてリンクにならないのだ? なんでだ? 

話は変わるが、正規表現であるパターンにマッチする文字列が複数あり、それをすべて取り出したいときにはどうすればいいのだろう? たとえば、今まさにやりたかったのは、httpでgetしたデータの中にあるリンク(a href) を全部取り出して配列に格納する、というようなケースだ。 パッと思いつかず、サラっと探しても見つからなかったので、a hrefの前で改行してファイルに吐き出し、そのファイルを読んで一行ずつ処理するというメンドクサイことをしている。 こんなことしなくてもできるよね・・・。

sedで一括置換できない

わけあって、以下のような置換をそこそこたくさんのファイルについて実行しなければならなかった。

%s/\n<br>/<br>/g


viで一個ずつ置換していたのだが、sedでやれば一括でできるだろうとやってみたが、できない。

sed -i -e 's/\\n<br>/<br>/g'


なんでだろう?

まあ、たいした数ではなかったので、一個ずつviで開いて置換をしていった。




twitterのbotが動かなくなった



以前使っていて特に不満はなかったのだが諸事情により解約したVPSを再度契約した。

レンタルサーバにしようか、VPSにしようか迷ったのだが、480円しか違わないのでお勉強のためも兼ねようと、VPSにした。

twitterのbotを復活させようとしてNet::Twitterを入れようと、いつものようにやったらエラーになった。

[hoge]# perl -MCPAN -e shell
Can't locate CPAN.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .).
BEGIN failed--compilation aborted.


調べるとモジュールのインストールが必要とのことだった。

yum install perl-CPAN


いつもおまじないのように実行していたが、モジュールを使っていたんだね。

さて、前に動かしていたbotが動かない。tweetができない。ascii文字とリテラルならいけるが、ファイルから読み込んだutf8の日本語がtweetできない。

自宅にあるcentosで、同じスクリプトが動いている。

Encodeのバージョンが、動かないVPSの方が新しい。

Centosはともに6.3だが、VPSは64ビット版、家は32ビット。

Perlのバージョンは同じ。

Net::Twitterも同じ。

Encodeのバージョンが違うというのが一番あやしい。下げてみようか・・・

でもそれより、動いているスクリプトがおかしくて、本来よくないやり方なのがたまたま動いていた、という問題な気がする・・・・

Net::Twitter::Liteにしたらうまくいった・・・。

原因は不明。

あー時間を空費した。

その後・・・

今度はblockしているユーザの一覧とその解除をする、OAuthを使うcgiを動かしたらこれも動かない・・・

最近apiの仕様が変わったという話は聞いていたが、そんな問題じゃない感じがする・・・

あれこれやってもどうしてもわからず、access token等を直接書いてblockしているユーザーを表示するスクリプトを動かしてみたら、数十秒かかる。

なんだこれ・・・