このブログを検索

2011/10/29

IPアドレスから国を判別する

ヘンなアクセスをしてくるIPはムカつくからiptablesでブロックしている。 whoisで、どこの国かなどを見る。 基本的に日本人以外には有用なものはないから、日本以外を全部遮断してもいいんだけど、それじゃ中国のGreatFWだもんね。
ftp.apnic.net/stats/apnic/delegated-apnic-latest


ちなみにここを見ると、どの国にどのIPアドレスが割り当てられているかはわかるようである。 日本以外をブロックするとかができるわけだ。 でも、インターネットに情報をさらしておきながら国内にアクセスを限るってのもどうかと思う。 あとIPアドレスが海外のものでも、日本人が海外の会社でサーバを借りたとか、 海外勤務の日本人が、とか、そういう場合もあるからやっぱりアドレスを管理しているISPの国を見てもあまり意味はないかもしれない。

2011/10/28

画像アップローダの作成

画像アップローダーを作ろう。 そういうサイトはたくさんあるけど、なかなか私の使いたいものがない。 以前使っていたサイトがあって、それがとてもよかった。 まず、画像はすべてサムネイルが表示される。 サムネイルといっても、結構大きめで、それで十分楽しめるくらいの大きさである。 PCの1画面で、3、4列くらいかな。 背景は黒。各画像の下には短いコメントが表示される。 多くの場合は何もないか、ごく短い。 投稿者だけでなく閲覧者もコメントをつけられるが、そのコメントはサムネイル表示時には表示されない。

画像の表示はglobでいいかな。 まずglobで画像を表示させてみると、大きさがまちまちになる。

これをプレビュー画面では同じ大きさに統一したい。 Windowsのexplorerとかpicasaとかのように。 さて、どうやるか。 ちょっと調べるといろいろ出てくる。 いつもはとりあえずなんでもいいから動くものに食いついてきたけど、 今回はどんな方法があるのかを調べて吟味してから使おう。

Image::Magick

GD

ImgResize

画像のサムネイルを作成する。

#!/usr/bin/perl
use strict;
use Image::Magick;

print "Content-type: text/html\n";
print "\n";
my @files = glob "./images/*.png ./images/*.jpg";
foreach (@files){
&MakeThumbnails($_);
}

print '<table border="0" cellspacing="3" cellpadding="3" width=80%><tr>';
my @files = glob "./thumbnails/*.png ./thumbnails/*.jpg";
my $count =0;

foreach (@files){
if($count % 5 <1){
print "</tr><tr>";
}
print "<td><img src=\"";
print $_;
print "\"></td>";
$count++;
}

print '</tr></table>';

sub MakeThumbnails{
my ($name) = @_;
my $dir = './thumbnails';
(my $newname = $name) =~ s/\/images/\/thumbnails/;
my $img = Image::Magick->new;
my $x;
$x = $img->Read($name);
$x = $img->Resize(geometry=>"200x150");
$x = $img->Write($newname);
}


サムネイルの作成と表示を同時に実施している。 表示(リロード)するたびにサムネイルを上書きするのはムダかもしれない。 枚数が増えてくると重くなるから、ページを分けたりする必要もあるだろう。 サムネイルをクリックしたら元画像を表示するとか、コメントをつけたり削除したりできれば、 表示部分はOK。

あとは、アップロード部分か。

perlでimagemagickを使いたくて、cpanでインストールしたらエラーになった。

調べると、yumでいれればうまくいくとのこと。

yum install ImageMagick-perl


なんで・・?

2011/10/26

セッション管理

yahoo, google, twitter, amazon... 今はどこのサイトもログインしてそのユーザ専用ページが表示されるようになっている。 前からこの仕組みをやってみたいと思っていた。 idとパスワードを入力させて、それをデータベースで参照して正しければ認証する。 実際は暗号化したり、SQLとかを使っているのだろうが、 原理だけを確認するなら、その辺は平文でテキストファイルでよい。

テキストボックス2つとボタンを作って、postさせれば認証機能は実現できる。 しかし問題はその先である。 単純に考えるなら、



  1. OKなら ok.htmlを表示し、NGなら ng.htmlを表示する。

  2. OKなら"ok"を、NGなら"ng"を引数としてauth.cgiを呼び、引数に応じて「ようこそ」「認証できません」などと表示する。

しかし問題なのは、認証の可否をどこかに維持しておかなければならないということだ。 それを「セッション管理」といって、perlにも CGI:Session というモジュールがある。 それを使えばいいのだろうが、複雑で、mySQLなどもからんでいてメンドクサイ。 もっと単純にできないだろうか? IPアドレスで管理するのはどうだろうか? いったんIDとパスワードを認証したら、そのときのuserのIPアドレスと、認証がOKであることを、ファイルに記録しておく。 サイトでは常にそのファイルを参照するようにして、認証されているかどうかに応じてページの表示を変える。 多分、「セッション管理」とか言うのも、同じようなことをしているはずだ。あとはポート番号を見たり、認証した時間を記録しておいて一定時間がたったらタイムアウトさせるとか・・・ でもあれか、natしてたりしたらIPアドレスで管理したら全部同じになっちゃうな。 セッションIDというのはHTTPプロトコルの仕組みで、それをサーバとクライアント(ブラウザ)で保持するようだ。だが、パケットキャプチャしても"session id"みたいなフィールドが見つからない。

セッション管理というのは、ステートレスであるHTTPプロトコルで状態管理をさせるための苦肉の策のようだ。セッションIDを生成して、それをクッキーを使ってクライアントに渡す。

#!/usr/bin/perl

use CGI;
use CGI::Session;

my $cgi = CGI->new;
my $session = CGI::Session->new(undef, $cgi, {Directory=>'./tmp'});
session->param('name','mysession');

print $session->header(-charset=>'UTF-8');

print   $cgi->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'http session test'),
$cgi->p('session id: '.$session->id.'<br/>',
'name: '.$session->param('name').'<br/>'),
$cgi->end_html;


とりあえずこのようなcgiを作って実行すると、session idが表示される。F5を押すたびにidは変わる。パケットキャプチャしてみると

Set-Cookie: CGISESSID=5d6b6c1c3248aa9b399060dcef4c4e58; path=/


のように、セッションIDがサーバからクライアントに返す HTTP OKのパケットの中に入っているのがわかる。・・・・・・で?

まずはcookieからだな。 cookieというのは、サーバ側から送信するもので、ユーザが閲覧するとユーザがcookieを無効にしていない限り勝手に保存される。 cookieには名前、値、ドメイン名、パスなどが設定できる。 ユーザが保存しているcookieは、環境変数

$ENV{'HTTP_COOKIE'}


で取得できる。 たとえば「名前」=「アクセス日時」というcookieを送信しておけば、次のアクセス時に「前回のアクセスは何月何日でした」などと表示できる。

amazon.co.jpにアクセスしたら、6個のcookieが保存された。

at-acbjp
session-id
session-id-time
session-token
ubid-acbjp
x-acbjp


値を見てもなんのことやらさっぱりわからないが、 サインインしたときにアカウントと関連付けて保存しておけば、どのアカウントかわかる。 どのサイトでも「ログインしたままにする」などのチェックボックスがついているが、 それをチェックしたときはcookieを見てアカウントの認証プロセスを飛ばすのだろう。 と、こう見てくるとperlの CGI::Session モジュールがやってることはたいしたことがないように思えてきた。 ただidを発行してcookieにセットしてるだけじゃないのか?




パソコンに写真がたくさん溜まってきて、特に見ないのだが捨てるのももったいなくてとってある。 これをwebに置くことにした。 いろいろあるけど、picasaのwebアルバムに落ち着いた。 いったん上げてしまうと、フォルダの階層が作れなかったり、削除や移動が一度にできなかったりとメンドクサイが、大量ファイル操作は一度ダウンロードして操作してアップロードするなどしている。それにしても重複ファイルの多いこと・・・メニューの「整理」を選ぶと、複数選択して削除や移動ができる。天下のgoogleがそんなことくらいできないわけないよな・・・

2011/10/25

sphinx

また新しいアドレスから sshアタックが来ていたので、iptablesに追加した。 しかしこれはイタチごっこになりそうだ。 と、誤って自分のアドレスをフィルタしてしまい、sshが固まった。 ヤバい・・・と、リモートコンソールがあることを思い出した。 しかし、なぜかアクセスできない。 と、「VNCコンソール」というものがあるのに気付いた。 よくわからないがこれだとアクセスできたのでiptablesの設定を直す・・・

denyhosts というソフトがあって一定の回数のアクセス失敗があると自動的に hosts.denyに追加してくれるものがあることを知り動かしてみたが、自分のアドレスが登録されてしまった。 過去のアクセス状況を見ているのだろうか。 それと、登録がホスト単位であること、拒否するのがsshdであることが気に食わない。 やっぱりiptablesでブロックごとドカンと跳ね除けることにした。

wikiを作ろうと思ったがsphinxというpythonでできたおもしろそうなのがあったので、 これを使ってみる。

yum install python-pip python-setuptools


をやってから、

pip-python install sphinx


をやる。 これだけでいいはずなのだが、インストール中にSyntaxErrorが出る。 最後は Successfully installed となっているので、

sphinx-quickstart


をやってみるが SyntaxError: invalid syntaxで動かない。 pythonのバージョンが古いのかと思ってupdateしてやり直したがダメ。 とりあえず、見送り。しょうがないからpukiwikiにする。 ダウンロードして解凍するだけ。 ちなみにPCにダウンロードしてFTPでアップロードした。 WEBにあるファイルをコマンドでダウンロードするにはどうすればいいのか? lynxを入れる?

sshdへの不正アクセスに悩んでいる人は多いようだが、私のように一人しか使ってないのなら、 もうsshdは止めておいて、使う時だけコンソールから入って起動したらいいんじゃないかな。もっというと全部リモートコンソールでやってしまってもいい。 とりあえずsshdできるユーザを制限。基本的にアクセス制限はデーモン単位でなくiptablesで出禁にする。・・・と、ムキになってアクセス制限をしてみたものの、 別にパスワードが割られたわけでもなし、 運用不能になるほど負荷があがったわけでもなし・・・。 止めてしまうよりもログを集めて分析したほうが面白いんじゃないかと思えてきた。

2011/10/24

587

自宅のPCでVPSのサーバにPOP3アクセスしてメールを受信することはできているが、送信できないことに気付いた。 VPSとはいえ自分で管理するサーバを持ったときに一番注意しなければならないのは不正アクセスである。 特にSPAMの踏み台になることは絶対に避けねばならない。 だから、少なくとも誰も彼もが私のVPSサーバにSMTPアクセスできるようになっていないことは確認できた。しかし自分のPCからはアクセスしたいので、いろいろ設定しているのだがどうもうまくいかない。

そのうち、/var/log/secure に大量の不審なアクセスのログが記録されているのに気付いた。 1秒おきにユーザ名を変えてsshアクセスしているログだ。アクセス元のアドレスは数個しかなかったのでwhoisでしらべてそれらを含むブロックをrejectした。 アドレスは中国、台湾、アメリカ、タイとバラバラである。 おそらく踏み台にされているのだろう。また、アクセスの仕方が非常に乱暴なのでごく単純なスクリプトを、興味本位で試しているようなものかもしれない。

whoisといえばいつもブラウザでANSIのwhoisを使っていたが、まてよと思ってcentosのコマンドでやってみたら検索できた。

どうしてもSMTPアクセスできない。 telnet 25 もできない。 PCでキャプチャしたら synを送ったきり応答がない。 サーバ側でtcpdumpしても何もこない。 ポートが開いていないのか、と、iptablesを見ると開いている。 でも、やっぱり25が開いていないとしか思えない、googleで探すとVPSの試用期間は25番が開かない、とある、 もしかして試用期間が終わったのに設定が解除されていないのか・・・?と思う。 nmapでスキャンしてみたら、やっぱり25は開いていなかった・・・

「さくら VPS sendmail 25 」などで検索してみると、どうやら「試用期間がすぎても25番が開かない」ということがあるようだ。 再起動したら直った、再起動してもダメだからポート番号変えた、などの情報があった。 再起動は何度かしたけどもう一辺やってみる・・・ダメ。 ポートを587に変える。 以前コメントにした DAEMON_OPTIONSで使用ポートを変更できる。 Addr=127.0.0.1 は削る。

DAEMON_OPTIONS(`Port=587,Name=MTA')dnl


iptables で 587をあけてiptablesをrestart。m4をやって、sendmailをrestartする。

送信できた・・・

この野郎~ッ!

しかしお陰様で sendmailやiptablesやnmapの使い方を勉強できたよ。

javamail入門

javamail入門という面白そうな本があったので、ちょっとやってみる。 javamailとかJAFとかを入れてみるがちゃんと動かない。 いつ入れたのか定かでないSDKを消して、入れなおす。
www.oracle.com/technetwork/java/javase/downloads/jdk-7u1-download-513651.html

インストーラが起動する。 デフォルトではデモをインストールしないようになっているが、インストールする。 インストール後、ユーザー登録画面が出てくる。 ついでなので登録しておく。

pathの登録が必要。

F:\Program Files\Java\jdk1.7.0_01\bin


言い忘れたけど Windows XPです。 昔書いたhello,world的なサンプルをコンパイルしてみる。

エラーになる。 ファイル名とクラス名が同じでないといけないのを思い出して、ちゃんと同じになっているものをコンパイルして動くことを確認する。

javamailは解凍したフォルダを program files\java に移しておき、 環境変数を登録する。 CLASSPATHのところに、mail.jarのフルパスを書く。

F:\Program Files\Java¥javamail-1.4.4\mail.jar;


ファイル名まで書かなければならない。 ということはjarを入れるたびに常にclasspathを書き換える必要があるのか?メンドクサイ・・・ と思うがそれはおいておく。

demoの msgshow.javaをコンパイルする。 classpathがうまく登録されていなかったり反映していないと、エラーが大量に出る。

ちなみに、WindowsXPの環境変数の変更は、 Program Files のように間にスペースがあっても""で囲んだりする必要はない。 コマンドプロンプトを起動していた場合は、そのままでは反映しない。(setをやってみるとわかる)。 コマンドプロンプトをいったん閉じて起動し直すと反映する。ログオフや再起動の必要はない。

実行してみた。

F:\Program Files\Java\javamail-1.4.4\demo>java msgshow -T pop3 -H example.com -U hoge -P xxxxxxx
--------------------------
MESSAGE #1:
This is the message envelope
---------------------------
FROM: John Lennon <john@example.com>
REPLY TO: John Lennon <john@example.com>
TO: hoge@example.com
SUBJECT: test
SendDate: Mon Oct 24 16:10:05 JST 2011
FLAGS:
X-Mailer NOT available

F:\Program Files\Java\javamail-1.4.4\demo>


感動。

じゃあ送信をやってみようと思ったら、うまくいかない。サーバはさくらのVPSを使っていたのだが、25番ポートがどうしても開かなかった。しかたがないので587番に変えた。ところがデモは25番を使っていて、ポートの指定はできなかった。さっそく改変の必要が生じた。しかしこんなのは簡単で、argvを格納しているところに新しい引数と変数を作り、

if (port != null)
props.put("mail.smtp.port", port);


とするだけでOKだった。ちなみにいじったのは msgsend.java である。

apple礼賛

appleは衰退するなどという無責任なことを書いた後にすぐ、appleを絶賛する人を見かけた(もちろんウェブで)。そしてあらためて感じたのは、appleが好きな人のapple礼賛ぶりの熱烈さである。でも、パソコンとかミュージックプレイヤーなどというものは料理で言えば皿などの器のようなものである。食事をご馳走になった後に、ひたすら「このお皿はいいですねえ。料理が引き立ちますねぇ、この模様がすばらしいですねぇ・・・、このナイフの切れ味とフォークの刺し易さには驚嘆します」などと料理について何もいわずに食器ばかりほめたら料理を作った人はガッカリするだろう。

わたしだって電球を発明したエジソンの業績はすばらしいと思う。蓄音機も、CDも、MDも、MP3も、インターネットも、FAXも、メールも、みんなすばらしい技術である。でも、appleを礼賛する人は、ブログを書いても音楽を聴いてもゲームをしても何をしても、「Macはいいな」「appleはいいな」と言っているような印象がある。それだけならいいが、たいていWindows否定がデザートのように追加される。

先ほど書いた閉鎖性ということについても、要するにナルシシズムであって、ハードウェアからソフトウェアそしてついにはコンテンツ売買までもappleで独占して悦にいっているのである。愛好者にしてみればこんなに気持ちのよいことはないであろう。しかし、そんなものは独裁者の築いた孤立した楽園のようなものである。そういう楽園を築き維持するためにはたいてい多数の犠牲者が存在しているものである。