2009/07/24

wildcard subjectaltname virtualhost

SSL と VirtualHost 関連で「どうなの?」的なことを問われたので
確か素敵まとめサイトがあったと思って検索したら
SSL/TLS で Namebase のバーチャルホスト
が出てきました
素敵!!
VhostTaskForce - CAcert Wiki
ここも素敵かな??

多分 Apache 用語ですけど
VirtualHost
1 つのウェブサーバで複数のウェブサイトを構築
IP address ベースと Name ベースのものがある
IP ベース VirtualHost
アクセスがあった IP address 毎に
サイト・コンテンツを指定して複数サイトがあるように見せる
IP address が複数必要なので場合によってはコストが高い
Name ベース VirtualHost
サーバーの名前毎にコンテンツを振り分ける VirtualHost
IP address が 1 つしかなくても複数のサイトが構築できる
HTTP 1.1 とかで Host というヘッダをクライアントは送るので
そこで判断してるんですよね?? きっと

で、こっから少し古い話

一方 SSL は TCP の接続の後にネゴシエーションするわけですが
ここにはまだ Apache 出てこないんで Host とかの内容見ません
SSL のネゴシエーションのときに分かるのは TCP までの情報なので
IP address とか port 番号とかです
なので、HTTPS でサーバが証明書を提示する際にどの証明書を提示するか
それを決める判断の基準も IP address とか port 番号しかありません

IP ベースの VirtualHost であれば IP address と port 番号毎に
1 つサイトが決まっているので証明書を提示してあげれば良いのですが
1 つの IP アドレスの下で Name ベースの VirtualHost をしてる場合
それら VirtualHost 達で 1 枚しか証明書が提示できません
なのでワイルドカードや SubjectAlternativeName などを利用して
1 枚で複数の FQDN に対応できる証明書が利用されています

古い話終わり

で、RFC 3546 で TLS 拡張で Server Name Indication ってのが定義されてるそうで
TLS レベルで接続したいサーバの名前を指定する仕組みが決められて
それ使えば Name ベースの VirtualHost でも問題無しに
1 Host 毎に 1 枚証明書を対応付けれて IP address もぉ要らないよ!
ということになっているみたいです

IE7 以降とか Fx 2 以降とか Opera 8 以上は対応してるみたいなんですが
携帯とかどうなんだろう??

更に、RFC 2817 では Upgrading to TLS という仕組みも定義されてるとか
HTTP 1.1 から TLS な世界に切り替わるみたいですが
ちょっと、ググっただけでは対応状況までは分かりませんでした

Server Name Indication が普及してくれると分かり易くていいですね

2009/07/22

epoll recv

Twisted が分からないのもそのはずで
やはり非同期ってのが良く分かっていないからなのでした
Twisted ドキュメント: Twisted による非同期プログラミング
ってのを twisted tutorial deferred で教わって
そもそも英文の方も読んだはずなのにちゃんと分かってなかったみたい

で、select とか epoll とかいう単語を
Voluntas さんに教えて頂くなどしまして
ちょっくら自分でも何か書いてみるかということで
RSS とか Atom とか取ってきてみようかなと
途中で悩んでググってみて
How epoll detect clientside close in Python? - Stack Overflow
のコードとか見たりしつつ

で、実際やってみたら HTTP の処理が面倒になっちゃったんで
まぁとりあえず epoll だけ実感できる感じで
from socket import socket, gethostbyname, error
from select import epoll, EPOLLIN, EPOLLOUT
from urlparse import urlparse

FEEDS = (
'http://d.hatena.ne.jp/Voluntas/rss2',
'http://kamo.typepad.jp/blog/index.rdf',
'http://takagi-hiromitsu.jp/diary/index.rdf',
'http://d.hatena.ne.jp/nishiohirokazu/rss2',
'http://www.nnar.org/feed/atom',
'http://d.hatena.ne.jp/CortYuming/rss2,'
'http://vim-users.jp/feed/atom/',
'http://blog.livedoor.jp/dankogai/atom.xml',
'http://d.hatena.ne.jp/Chikirin/rss',
'http://thisistanaka.blog66.fc2.com/?xml',
)

ep = epoll(1024)
sockets = []
feeds = {}

for feed in FEEDS:
feed_data = urlparse(feed)
hostname = feed_data.netloc
path = feed_data.path
s = socket()
s.settimeout(0)
try:
s.connect_ex((hostname, 80))
except:
continue

fileno = s.fileno()
feeds[fileno] = (hostname, path, s)
ep.register(fileno, EPOLLOUT)

while feeds:
for (fileno, event) in ep.poll():
s = feeds[fileno][2]
if event == EPOLLOUT:
s.send("GET %s HTTP/1.1\nHOST: %s\n\n" %
(feeds[fileno][1], feeds[fileno][0]))
ep.modify(fileno, EPOLLIN)
elif event == EPOLLIN:
s.setblocking(1)
print s.recv(1024)
del feeds[fileno]
ep.unregister(fileno)
実行する度に結果が違うはずで
それは返事が来た順番で処理できてるからなはず

FEEDS の分だけ socket 張って
epoll で監視して受けとれるようになった奴から 1KB だけデータ読んでます
Python の場合 socket object には connect_ex って method がありまして
こいつは exception ではなくて error の値を吐くんだそうです

が、connect_ex は接続先が resolve できなかったときだけ
exception 吐くという仕様となっていたので
結局 try except してしまいました

あと、ほんとは socket.fromfd とかで socket 呼んだ方がいいのかも
だけど別の場所で socket を覚えさせたりしないと
    ep.modify(fileno, EPOLLIN)
IOError: [Errno 9] Bad file descriptor
って言われたりして
unregister した瞬間に socket が葬り去られてしまってるんでしょうか
無駄に覚えさせといても動いたんですが折角なんで
socket も feeds の中に入れてみました
modify ってあったから使ってみたんだけどこれが間違ってる可能性もあり

で、更に recv するんじゃなくて socket を thread に渡したりすると
きっと凄い格好の良いことになるに違いありません
Twisted が何してるか少し分かったかも
Twisted の reactor は default だと selectreactor ってのが呼ばれてるけど
他にも色々、例えば epollreactor とかもあるみたいなので
それぞれ reactor 毎に色々してるに違いない、違いないんだけど.....