2008年10月7日火曜日

Base64符号化で簡単な組み合わせを編み出す

頭に結論を書いてしまうと、一番簡単なのは
UUU(平文で3文字) ⇔ VVVV(Base64で4文字)
だと思うんです。もちろん「UUUUUU」 ⇔ 「VVVVVV」 もあり。
※追記:「DDD」⇔「RERE」 も覚えやすい。
 
 

Base64への道のり


ちょっとしたテストをTelnetでしたいときに、Base64エンコードが必要なケースがある。そんなときにツールやPerlを呼ばなくても簡単にできたらよいなと思って仕組みを調べてみた。
    平文はこのようなプロセスを経てBase64文字列になる
  1. 各文字をASCIIコードに変換する

  2. 得たASCIIコードを2進数(8ビット)に変換して並べる

  3. 並んだビット文字列を6桁(6ビット)ずつ区切る、最後足りない分は0をつける

  4. 6ビットの文字列をBase64文字列変換表を参考にBase64文字列に変換する、これは一応4文字づつ

  5. できた文字列が4の倍数に満たない場合は=(イコール)をパディング、符号化完了


 

Base64変換について、普通はperl一行野郎などで変換してもらう。
$ perl -MMIME::Base64 -e "print &MIME::Base64::encode_base64(hogehoge);"
encode_base64関数でhogehogeを変換して表示する。自分用メモ

 

最小公倍数の24ビットを軸にする


変換の仕組を調べて、暗算するには相応の努力が必要だということが分かったので楽な方法を考えることにした。。
 
「ASCII = 8ビット」、「Base64 = 6ビット」 ということは公倍数の24ビットの所で丁度キリがよくなる。
つまり平文3文字をBase64で符号化すると4文字になり、その組み合わせは1対1と言うことになるので、Base64変換表からよさそうなのを探す。
 
「010101 = V」
 
これならどこで切っても同じになる、これがよさそう。
 
 

変換して確かめる


さて、Base64なので4文字並べて「VVVV」
これをそれぞれ6ビットに変換して「010101 010101 010101 010101」
8ビットに繋ぎかえて「01010101 01010101 01010101」
ASCIIに変換すると「UUU」
 
 

3文字単位ならいくら並べてもOK、たまに使い道があるかもしれない。他にも簡単な組み合わせがあったら是非教えて欲しいですね。
 
 

まとめ


結局、Basic認証ではコロンがいるし、メールアカウントではアットマークが必要なことが多い、それがネックだ。
一応3文字のユニットとして扱えば覚えておけないこともないかも知れないので書いておこう。
 

「U:U = VTpV」
「U@U = VUBV」
 

よし、メールは複数ドメイン環境では無理だな。

2008年10月3日金曜日

telnet があれば、サーバ間でファイルの転送ができる(後編)

前編からの続き
telnet があれば何でもできる! と言ってみたかっただけですが。
 

ということで、telnet2本使いによるFTPファイル転送を実際にやってみる。
実験にはIISのFTPサーバを使い、サーバ間のファイル転送ができるかを確かめた。
 
 

突然つまづく、最近はデフォルトセキュア(寄り)なのか…


リハーサルとして一通り試していたら、PORTコマンドの所でどうしてもつまづく。
パケットキャプチャしたら、PORT発行後もIPによる通信すら しに行っていない様子。IISの設定を見直すためにMSへ。

 
なるほどそうか。最近はそんなことやらないからか、単に脆弱性の脅威からか、デフォルト設定ではできない。レジストリをいじってFTPサービスを再起動しないといけなかった。
レジストリ変更箇所は下記。









ファイル受信側
(PASV)
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSFTPSVC\Parameters\EnablePasvConnFrom3rdIP=1
※第3者からのデータコネクションを許可する
ファイル送信側
(PORT)
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSFTPSVC\Parameters\EnableDataConnTo3rdIP=1
※第3者あてへのPORTコネクション接続要求を受け付ける。

これで問題はなかろう、よそへのPORTコマンドもちゃんと受け付けてくれる。
 
 

そして実験へ


test.txtと言うファイルを転送してみる。



































ファイル受信側ファイル送信側メモ
USER hogehoge
PASS *****
 
230
USER hogehoge
PASS *****
 
230
ユーザ認証してログインOK
PASV
 
227 Entering Passive Mode (xxx,xxx,xxx,xxx,xx,xx).
 待ち受けポートを決定する。
xxxはIPアドレスと待ち受けポート
 PORT xxx,xxx,xxx,xxx,xx,xx
 
200 PORT command successful.
データ転送用のセッションが確立
stor test.txt
 
125 Data connection already open; Transfer starting.
 STORでローカルに空ファイル"test.txt"作成、
データの受け入れ準備
 
125 Data connection already open; Transfer starting.
226 Transfer complete.
retr test.txt
 
150 Opening ASCII mode data connection for test.txt(23 bytes).
226 Transfer complete.

RETRで "test.txt"ファイルを転送、
受信側は待ち構えていた"test.txt" にASCIIデータとしてデータを送り込んで完了

 

OK、うまく行った。
 
 

次はどうしよう。
定番の「telnet があれば メールの送信ができる」や、「telnet があれば HTTPコンテンツを受け取れる」、あたりでやっておきたい。

2008年10月2日木曜日

telnet があれば、サーバ間でファイルの転送ができる(前編)

telnet ですかー!?
と、分からないかもしれないネタはこの辺にして、「telnet があれば、サーバ間でファイルの転送ができる(前編)」と題して FTP (File Transfer Protocol) の仕様を確認するコラム。
 
 

前置き、PASVコマンド


FTPというと、通常のPORTコマンドを使うやり取りを初めて理解したときは驚いた。
「PORTコマンドの発行を受け付けたサーバは、接続元ポートTCP/20 でクライアントにむけてTCPセッションを張りに来る。」
そうやって接続されたセッションがデータ転送ポートとして、ファイルリストのテキストデータや、バイナリデータの転送に使用される。
 

嘘やん、そんなのこちらポート空けてないのにどうすんの?って思う節があるかもしれないが、最近のファイアウォールやルータはその辺をヨロシクやってくれて、意識しなくてよいようになっている。
しかしそうではないルータの下にいるFTPクライアントの為に、PASVを使うという手順がある。
 
 

FTPサーバがPASVコマンドを受け付けると、任意のポートでLISTEN のTCP状態を取り、クライアントに通知します。
 
    [PASV] → [227 Entering Passive Mode (192,168,10,15,239,11)]
 
カッコ内がカンマ区切りで、IPアドレス・待ち受けポートです。このメッセージからは「IPアドレス:192.168.10.15、ポート:61195」 でLISTENしますよ、と言うこと。ちなみに 61195 は 「239 * 256 + 11」 で計算します。
 
 

PASVに割りこんだらどうなるの?


PASVでポートの通知を受けたFTPのクライアントは、当然LISTENしているポートにTCPセッションを張りに行き、データはこのポートから送信されます。
 
と、ここでPASVで教えてもらったポートに telnet で接続するとどうなるか試した(※実験はPASVも telnet で発行しました。)ら、ちゃんとセッションが張れる。
そのまま最初に接続したコマンド用のセッションで、LISTなど発行すればPASVで張ったほうのセッションからリストデータが、RETRをすればファイルの中身が流れてくるといった具合。
 

基本的に接続元の制限などない模様なので、これはこれで危なっかしいとも思えるが、もうちょっと突っ込んで考えてみる。
 
 

PORT と PASV の組み合わせで、と思ってRFCを参照する


使わないから意識していなかったが、FTPはサーバ同士のデータ転送という役割を与えられたプロトコルでもある、と言うのを形だけ知っていた。
上の割り込み実験から、「PASV で待ちうけ、PORTで接続」 とすればサーバ間の転送ができるんじゃないかと思って、RFCを読んでみた。
   RFC:959(原文)(日本語訳)
 

すると、「5.2. CONNECTIONS」 の所にしっかり書いてあった、今でこそ一般的ではないやり方だけど、RFCでは一番シンプルなFTPの使い方としてサーバ間のデータ転送が紹介されている方法だった。
 
 


telnet2本張って サーバ間のデータ転送


コントロールはクライアントから、データの転送は2台のサーバ間で。
サーバA(SV-A)からサーバB(SV-B)にファイルを転送したい場合、ざっとこういう手順で達成できるはず。図が崩れてたらごめんなさい、Firefoxだと一応きれい。
 

















┌──────┐        ┌──────┐
│ SV-A │ │ SV-B │
└──────┘ └──────┘
↑ ↑
│ │
│telnet 21 │telnet 21
│ ┌──────┐ │
└←│ Ctrl │→┘
└──────┘
コントロールするクライアントから、両方にtelnet でFTPログイン
                        LISTEN
┌──────┐ ┌──────┐
│ SV-A │ ★ SV-B │
└──────┘ └──────┘
│ ↑
│ │
│ │PASV
│ ┌──────┐ │
└─│ Ctrl │→┘
└──────┘
SV-B にPASVコマンドを発行、ポートをLISTENさせる
                        LISTEN
┌──────┐ ┌──────┐
│ SV-A →───→★ SV-B │
└──────┘ └──────┘
↑ │
│ │
│PORT(SV-B) │
│ ┌──────┐ │
└←│ Ctrl │─┘
└──────┘
SV-Bが待ち受け中なので、SV-AへPORTコマンドを送る。送信内容はSV-BのIPアドレスとポート
すると、SV-A と SV-B の間でFTPデータ用のセッションが確立するはず
┌──────┐→data→┌──────┐
│ SV-A ====== SV-B │
└──────┘ └──────┘
↑ ↑
│ │
│RETR(File) │STOR(File)
│ ┌──────┐ │
└←│ Ctrl │→┘
└──────┘
後編作成後に認識間違いを修正。図も修正。
初版ではここの解釈に嘘があった、STORで待ち構え、RETRで送るというオペレーションが必要ということだ。
 
(初版)データコネクションが確立したら、STORコマンドでファイルの転送が行えるはず。
RFCではSV-B側でRETRコマンドが必要とあったが、この辺がよく分からない。

 

さて、手元に実験できるサーバがないので今度試してみよう。
後編につづく

2008年10月1日水曜日

VirtualBox のVRDP接続を試してみる

サンマイクロシステムズ の VirtualBox という仮想化ソフトがありますが、これが マイクロソフト の リモートデスクトッププロトコル(RDP) が使えるということなので、試してみる。
 
 

VirtualBox 側で設定を行う


設定は仮想マシンごとにできます、ポートの重複に注意。
[caption id="attachment_967" align="alignnone" width="500" caption="画像:VRDPの設定画面"]画像:VRDPの設定画面[/caption]
 
デフォルトの "3389" ではWindowsの標準と被ってしまうので、この例では "13389" ポートを使用するようにセットアップ。VirtualBox側の設定はこれだけでOKでした。
 

リモートデスクトップクライアントから接続する


では適当なリモートデスクトップのクライアントから接続してみる、ここではVistaから。
例ではローカルホストだけど、他のIPからでも問題なかった。忘れないようにFireWallのポートもあけておく。
[caption id="attachment_968" align="alignnone" width="403" caption="画像:リモートデスクトップ起動"]画像:リモートデスクトップ起動[/caption]
まずはクライアントを起動して、
 
 

[caption id="attachment_969" align="alignnone" width="479" caption="画像:ローカルホスト宛にポートを指定して接続"]画像:ローカルホスト宛にポートを指定して接続[/caption]
接続先のIPアドレスにコロンで区切って、VirtualBox の VRDP待ち受けに設定したポートを指定。
 
 

[caption id="attachment_970" align="alignnone" width="300" caption="画像:VirtualBoxのBIOS画面"]画像:VirtualBoxのBIOS画面[/caption]
VirtualBox のBIOS画面にリモートデスクトップ接続しているのがわかるだろうか。
今回は認証をNullにしているのでユーザ名などは必要ない。
 
 

適当なOSを起動してみる


ということで手元の slax-ja を起動する。
[caption id="attachment_971" align="alignnone" width="300" caption="画像:slax起動直後"]画像:slax起動直後[/caption]
違和感バリバリの斬新な光景だ。タイトルバーの能天気な「リモート デスクトップ」がポイント高い。
 
 

[caption id="attachment_972" align="alignnone" width="300" caption="画像:Xを起動"]画像:Xを起動[/caption]
デフォルトのウインドウマネージャを起動してみる。さすがに自動で画面は伸長しないいけど、ちゃんとリモートデスクトップっぽい。
 
 
 

なかなか面白い機能だと思った。

2008年9月26日金曜日

cronとrun-partsを使って、任意の順番でスクリプトを実行する

Linux (確認はCentOS4と5) をインストールしたら、 "/etc/crontab" に最初からrun-partsの実行が登録してある。
※もしも入ってない場合は、特殊なケースかと思うけど、「crontab」 パッケージに入っているので入れます。
 

crontab はこんな感じ。
・
・
# run-parts
01 * * * * root run-parts /etc/cron.hourly
59 4 * * * root run-parts /etc/cron.daily
5 4 * * 0 root run-parts /etc/cron.weekly
9 4 1 * * root run-parts /etc/cron.monthly

 
 

run-parts ってなにさ


引数でディレクトリを指定すると、ディレクトリ内の実行可能ファイルを名前順に実行する コマンドです。
「run-parts /etc/cron.daily」 と指定があったら、 "/etc/cron.daily/"以下の実行対象を全部ですが一つずつ実行してくれます。
サブディレクトリは無視、あと、ファイル名も使える文字が決まってたはず、"英数-(ハイフン)_(アンダーバー)"あたりだったかな。
 
この名前順という性質は利用できる。
 
 

運用専用ディレクトリを作る


さて、run-parts に食わせる運用的なスクリプトの入れ物を作ります。
大体下記のような構成のツリーを作りますね、共通場所とログ場所は好みですけど作っといたほうがあとあとメンテナンスしやすいと思う。
work/ (cronの実行ユーザが読めればどこでもいい)
├config/ -----★共通設定ファイル置き場、"."(ドットコマンド)でスクリプトから読み込む
├logfiles/ -----★共通のログフォルダ
│
├dailyjob/
-----★日次で実行したいスクリプト入れ
└weeklyjob/ -----★週次で実行したいスクリプト入れ

 
 

dailyjob には何をいれるの?


使い方の一例としてはこんな感じ。

dailyjob/ 中身の例は下記ファイルたち
├00_timestamp -----★ログファイルに時刻書き込み
├05_serverstats -----★サーバのステータス出力とか
│10_stopapp -----★バックアップしたいアプリを止める
├20_appbackup -----★アプリデータのバックアップ
├30_startapp -----★止めていたアプリをスタート
└40_logbackup -----★ログなどのバックアップ

 

このケースで想定しているのは
「バックアップ前に動いてるアプリは止める必要がある、アプリは影響ある部分のバックアップが終わったらすぐ再開して、影響がない部分はゆっくりバックアップすることにしたい。また、バックアップはサーバの情報取得とかぶると重いからいや。」
という状況。(欲張りかも…)
 
ファイル名を数字で始めているので、実行される順番をコントロールできる。
あとはそれぞれのスクリプトをしっかり作っておけばOK、別々にCronだと、実行時間がかぶったりしたときの調整が大変なので、私は最近こんな感じで設定。
 
後から追加("05_" なんかはそう) できるようにちょっと数字は飛び飛びで設定しておくのもよいかもしれない。
"00_timestamp" は趣味で。
 
 

config/ ディレクトリに共通で読ませるファイルを置く


これも趣味だけど、ここに置くファイルにログファイルのパスとか使いまわせるファンクションを定義したファイルを置いておき、全部のスクリプトから "."(ドットコマンド) で読ませるようにする目的で使います。
 
もっと分かりやすいやり方もあるんでしょうけど、自分がメンテする分には今のところこの構成が楽かな。
 
ほか、run-partsは全部のスクリプトに共通の引数を渡すことができるので、例えば実行されるスクリプト側で 2 を渡せばデバッグ出力ONとか、1 もらわないと何もせず終了するなども共通で設定しておくといいかも。

Firefox3を自動更新したらアドオンが無効になったので、互換性チェックを一時 的に無効にする

Firefoxの 3.0.2 のリリースがあったので更新チェックをかけた。
3.0.3 がすぐに出たけど同じ方法で keyconfig は使えた。

 

それはいいんだけど、ボサッとしてたら大事な大事なアドオン、「keyconfig」が "3.0.2では対応してない" と、無効になってしまった。
正確に言うと更新前の確認で "keyconfig無効になりますよー" と教えてもらったけど、ちょっと我慢すればkeyconfigの更新があるだろうと軽くUpdate。
 

FireFox の再起動後、、、
Donutライクなファンクションキーでのタブ移動※が無かったら30秒と堪えられなかったので この keyconfig を有効にする手段を探す。

※ [Ctrl + (TAB|Shift + TAB)] or [Ctrl + (PageUP|Down)] にも同様の機能の割当てがあるけど、しっくりこない。

 


アドレス欄にabout:configを入力して、適当に "addon" とか "check" で絞り込む。
extensions.checkCompatibility というのがヒット。キー名をGoogleって調べたらこれっぽいね。
キーがないケースもある模様、その場合は 真偽値(ブーリアン)で作れとある。うちにはあったが何かのアドオンが作ってくれたのかな?
 

という事で、extensions.checkCompatibility の値をダブルクリックして「false」に変更。めでたしめでたし。
 

この手は自己責任で。
誤動作しそうなアドオンは開発者さんからのバージョンアップ(対応)を待つことを推奨、どーしてもいるやつだけ救済する目的で使いましょう。危ないのはとりあえず手動で無効に設定。

2008年9月24日水曜日

Googleが10周年で記念サイトオープンだそうな

Google10周年とのことで、記念サイトで歴史が一望できる。

Google 10th Birthday
http://www.google.com/tenthbirthday/


 

当時はYahoo! のようなディレクトリ型検索しか使ってなかった。
昔のロゴをみて思い出したけど、確か Google を見て「GeoCities がまた何かくだらんこと始めた」と思った記憶がある。
 

出だしの G しか合ってないやんか自分。