2009/07/02

python resolv

Python を使って名前を解決するぞ! と思ったんですが
初心者はそんなことのやり方も知りません
ググってみたら最初に出てきたのが
Ruby, Pythonで並列に逆引きを行う - bkブログ
Ruby と Python の threading の比較を resolve でしてるページでした
で、中で使ってるのは socket.gethostbyaddr

そっか、socket かと思い試してみました
>>> import socket
>>> socket.gethostbyaddr('www.google.com')
('jp-in-f99.google.com', [], ['66.249.89.99'])
>>> socket.gethostbyname('www.google.com')
'66.249.89.99
あら、1 つしか答えてくれません
$ host www.google.com
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 66.249.89.99
www.l.google.com has address 66.249.89.147
www.l.google.com has address 66.249.89.104
www.l.google.com has IPv6 address 2001:4860:c004::68
こういうの期待してたんですが

あれー、と思って検索語を変更 -> python dns
dnspython home page ってページが top に
ん〜、だったら最初から pypi 使えよって話な気もしますが
インストールしてみて
>>> import dns.resolver
>>> [ i.address for i in dns.resolver.query('www.google.com') ]
['66.249.89.99', '66.249.89.104', '66.249.89.147']
>>> [ i.address for i in dns.resolver.query('mail.google.com') ]
ん〜、何か可愛くない

一歩戻って gethostbyname でググると
Manpage of GETHOSTBYNAME ってだから man 見ろよと
でも
gethostbyname*() と gethostbyaddr*() は過去のものである。アプリケーションでは、代わりに getaddrinfo(3) と getnameinfo(3) を使用すること。
と書いてあります
>>> import socket
>>> socket.getaddrinfo('www.google.com', 80)
[(2, 1, 6, '', ('66.249.89.147', 80)), (2, 2, 17, '', ('66.249.89.147', 80)), (2, 3, 0, '', ('66.249.89.147', 80)), (2, 1, 6, '', ('66.249.89.104', 80)), (2, 2, 17, '', ('66.249.89.104', 80)), (2, 3, 0, '', ('66.249.89.104', 80)), (2, 1, 6, '', ('66.249.89.99', 80)), (2, 2, 17, '', ('66.249.89.99', 80)), (2, 3, 0, '', ('66.249.89.99', 80)), (10, 1, 6, '', ('2001:4860:c004::68', 80, 0, 0)), (10, 2, 17, '', ('2001:4860:c004::68', 80, 0, 0)), (10, 3, 0, '', ('2001:4860:c004::68', 80, 0, 0))]
おぉ、こ、これは

これは socket の reference を見ろということだろということで
>>> import socket
>>> socket.gethostbyname_ex('www.google.com')
('www.l.google.com', ['www.google.com'], ['66.249.89.147', '66.249.89.99', '66.249.89.104'])
_ex って
なんか、まぁ、これで、解決したのかしら...

2009/07/01

nginx ssl

2009/07/26
"ssl_prefer_server_ciphers on" があると core dump する
というレポートがあったので外してみたところ
IE と仲良くできているようです
nginx ssl_prefer_server_ciphers and MSIE 7.x core dump

2009/07/13
以下の方法だと IE と仲良く HTTPS できてませんでした
私の環境が悪いのかもしれないの情報募集中



Web Server を立てないとなってことになりました
  • 2 つの HTTPS サーバを手軽に構築したい
  • 片方は静的コンテンツ表示のみ
  • 片方は単純なリダイレクトのみ
Apache/Lighttpd/Nginx 辺りが候補かなぁと思っていたんですが
twitter で公募したら Nginx に決定

nginx で検索したら official が出てくるんで source を download
CentOS5 で開発環境も入れてない環境だったので
openssl-devel gcc pcre-devel make を rpm で入れて configure
--with-http_ssl_module って option を付ければ HTTPS ready な Makefile のできあがり
make && make install しました

設定ファイルは conf って directory に入ってる conf/nginx.conf
conf/nginx.conf に設定例が沢山書いてあるのでこれだけ見たら設定できてしまいます
http とか server とかのキーワードと {} で範囲指定して特定の設定してます
http の中に server を沢山書けばいいみたい
conf には沢山 file があるけど include で読み込んでいます

Virtual Host の方法ですが、conf/nginx.conf に
    # another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
とあるので
IP-based であれば server 毎に somename:8080 という指定で OK のようです。
log ファイルなんかも server の中で個別設定できます。

SSL の設定ですが、更に下の方に
    # HTTPS server
#
#server {
# listen 443;
# server_name localhost;

# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_timeout 5m;

# ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}
おぉぉ、完璧。
サーバ証明書に中間 CA 証明書が必要な場合、
apache でいうとこの SSLCertificateChainFile を設定したい場合は、
NginxHttpSslModule を見ると
サーバ証明書の後に中間 CA 証明書を連結すれば OK のようでした。

リダイレクトに関しては NginxHttpRewriteModule を見ると
適当に条件分岐した後 rewrite というコマンドで何を何処に飛ばすか設定で OK みたい
apache の mod_rewrite より分かりやすい
今回は無条件に redirect させたかったので
if とか使わずいきなり rewrite 書いてみました

で、関係箇所の抜粋が
http {
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:!EXP:!ADH:!LOW:!SSLv2:!MD5;
#ssl_prefer_server_ciphers on;

server {
listen 10.0.0.1:80;
server_name sample1;
access_log logs/sample1_access.log;

rewrite ^(.*)$ https://sample1$1 permanent;
}

server {
listen 10.0.0.2:80;
server_name sample2;
access_log logs/sample2_access.log;

rewrite ^(.*)$ https://sample2$1 permanent;
}

server {
listen 10.0.0.1:443;
server_name sample1;
access_log logs/sample1_ssl.log;

ssl on;
ssl_certificate ssl/sample1.crt;
ssl_certificate_key ssl/sample1.key;

location / {
root html;
index index.html index.htm;
}
}

server {
listen 10.0.0.2:443;
server_name sample2;
access_log logs/sample2_ssl.log;

ssl on;
ssl_certificate ssl/sample2.crt;
ssl_certificate_key ssl/sample2.key;

rewrite ^(.*)$ https://sample3$1 permanent;
}
}
秘密鍵と証明書は ssl ってフォルダ作ってつっこみました
80 番に来たら 443 番に飛ばして
それぞれコンテンツ出すか他サイトに飛ばしています
ssl_ciphers  ALL:!EXP:!ADH:!LOW:!SSLv2:!MD5;
ってのは SSLCipherSuite 参照

あと、起動と終了のスクリプトどうしようかなぁと思いまして
nginx startup-script で検索してみたら
fujishinko 雑記帳 : CentOS nginx の起動スクリプト
何と
pid file は conf/nginx.conf 内で pid という変数で指定できるので
これで何もかんも完璧になってしまいました

Nginx すごい!

2009/06/28

virtualenv activate

pyOpenSSL に実装されてる機能の数が残念だというお話は
今日も明日もググったー: 16進数 python
でさせて頂いてあったわけですが
以前に証明書の署名アルゴリズムを string で表示させる method と
Connection からサーバの提示する証明書のリストを list で返す method と
見様見真似で実装してみて投稿してみたんですけど
「メソッド足して欲しかったらテスト書けよテスト」
って言われて
「えぇ〜テストなんて書いたことないし、プログラマじゃないしぃ〜」
と自暴自棄になっていた時期もありました

で、テスト書こうということであれば真っ新な環境の方がいいなぁと思い
そういうのって virtualenv とか使うんだって試したことあったんですが
既に忘却の彼方だったので復習する為に検索することに
でまぁ、やることっつったら install して env 作って activate するだけみたい
仕組みだったら
virtualenv - def __mopemope__(self, *args, **kwargs):
で解説されてるし!
あっ、っていうか
モダンPython開発環境入門 - def __mopemope__(self, *args, **kwargs):
こっちの方が興味ありですし!

で、pip? って思ったんですが easy_install (setuptools?) の次らしいです
Why I like pip かを語ってらっしゃる方もいらっしゃることだし
最近人気の、easy_install よりも高機能なインストールコマンド。」と言われたら
とりあえず試してみたくなるのが人情というもの
とりあえずだから bootstrap とか言わずに
cd /tmp
wget http://www.python.org/ftp/python/2.6.2/Python-2.6.2.tar.bz2
tar xfj Python-2.6.2.tar.bz2
cd Python-2.6.2
./configure --prefix=/tmp/local
make -j 4
make install

cd /tmp
wget http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.3.3.tar.gz
tar xfz virtualenv-1.3.3.tar.gz
/tmp/local/bin/python virtualenv-1.3.3 sandbox
source sandbox/bin/activate

wget http://pypi.python.org/packages/source/p/pip/pip-0.4.tar.gz
python pip-0.4/pip.py install ipython
とりあえず ipython 入っちゃった

pyOpenSSL のテストを試してみないとなぁと思ったので
cd /tmp
wget http://jaist.dl.sourceforge.net/sourceforge/pyopenssl/pyOpenSSL-0.9.tar.gz
tar xfz pyOpenSSL-0.9.tar.gz
cd pyOpenSSL-0.9
python setup.py build
python setup.py install
と install してみて
$ cd test
$ python test_ssl.py
............
----------------------------------------------------------------------
Ran 12 tests in 1.009s

OK
$
テスト通ったー!! ってまだ何もしてないですけどね

これで patch あてたもんを install してテスト書いてみました
get_signature_algorithm 向けには用意されてる証明書の署名アルゴリズムで確認
sha1WithRSAEncryption で署名されてました
    def test_get_signature_algorithm(self):
cert = load_certificate(FILETYPE_PEM, self.pemData)
self.assertEqual(cert.get_signature_algorithm(), "sha1WithRSAEncryption")
get_peer_cert_chain 向けには verisign.com に繋いで
  • get_peer_cert_chain の結果の最初が get_peer_certificate の結果と合うか
  • get_peer_cert_chain の結果のそれぞれの CN が想定されるものか
を確認
EV SGC ですねぇ
    def test_get_peer_cert_chain(self):
context = Context(SSLv3_METHOD)
client = socket()
client.connect(('verisign.com', 443))
clientSSL = Connection(context, client)
clientSSL.set_connect_state()
clientSSL.do_handshake()
cert = clientSSL.get_peer_certificate()
certs = clientSSL.get_peer_cert_chain()
self.assertEqual(dump_certificate(FILETYPE_PEM, cert),
dump_certificate(FILETYPE_PEM, certs[0]))
self.assertEqual(certs[0].get_subject().CN, 'www.verisign.com')
self.assertEqual(certs[1].get_subject().CN,
'VeriSign Class 3 Extended Validation SSL SGC CA')
self.assertEqual(certs[2].get_subject().CN,
'VeriSign Class 3 Public Primary Certification Authority - G5')
他の test でも verisign.com に繋いでるんで無駄な気もしつつ
でも test って分けた方がいいの? と思いつつ
こういう場合はどうしたらいいんだろうなぁ

やぁ、virtualenv 素敵だなぁ