奇了怪了
Thursday, June 25th, 2009在这个国度,政府以道德的名义加上行政力量来处罚能搜索出淫秽内容的搜索引擎,却全然没有去反思人们为何会搜索这些内容,更没有去积极的去处罚淫秽内容的发布者。这和藏污纳垢又有何区别!四千年前便有了“大禹治水”,至今却仍然不知疏导。这是为什么?集权暴力?集体健忘?千里之堤也有溃于蚁穴的那天。
在这个国度,政府以道德的名义加上行政力量来处罚能搜索出淫秽内容的搜索引擎,却全然没有去反思人们为何会搜索这些内容,更没有去积极的去处罚淫秽内容的发布者。这和藏污纳垢又有何区别!四千年前便有了“大禹治水”,至今却仍然不知疏导。这是为什么?集权暴力?集体健忘?千里之堤也有溃于蚁穴的那天。
稍微测试了一下,用Python写一个IPv6的XML-RPC客户端比较简单:
import xmlrpclib server = xmlrpclib.ServerProxy('http://[::1]:4444/usermgmt') print server.list_users({'namespace' : 0})
如上,如果是loopback,只要把127.0.0.1换成IPv6的表示方式[::1]即可。对于ruby,可惜就不是这样了。如果依样画葫芦写出如下代码:
require 'xmlrpc/client' server = XMLRPC::Client.new2('http://[::1]:4444/usermgmt') p server.call('list_users', {'namespace'=>0})
那么我们很可能得到下面一条错误信息:
getaddrinfo: Name or service not known (SocketError)
在线文档中可以看到,XMLRPC::Client.new2的代码,可以确信它假设url是IPv4的。不过,不要气馁。我们还有一个最基本的接口:XMLRPC::Client.new,指定host为”::1″(注意,不要加中括号),path设为”/usermgmt”,注意前面有个”/”,如下:
server = XMLRPC::Client.new('::1', # host '/usermgmt', # path 8010, # port nil, # proxy_host nil, # proxy_port nil, # user nil, # password false, # use_ssl nil) # timeout (default: 30)
这个礼拜还是比较充实的,至少很久没有这么充实了。终于弄出一个补丁,使得我们的服务器可以支持IPv6。基本的PoC已经在上周完成。因为没法等OpenSSL 1.0.0的正式release,于是只能自己改代码。手工创建 socket然后把accept()之后的connfd包装在一个BIO里面,所谓“曲线救国”了。本周只是把那些已经验证过的逻辑加到库中。本以为没啥问题的小事,却折腾了整整五天。
第一个问题出在Buffered IO上。代码里面原来用的是BIO_gets()来读数据,而这个函数只在Buffered IO中才有效。一开始我自己写了个BIO_readline(),想想不太好,于是在自己的BIO上又chain了一个BIO_f_buffer(),这样不改变原来的逻辑。
sbio = BIO_new_ssl(server->ctx, 0);
bbio = BIO_new(BIO_f_buffer());
sbio = BIO_push(bbio, sbio);
有了这一层bbio后,HTTP连接开始正常工作,而HTTPS的时候却一直SIGSEGV,无论32/64位机器,无论OpenSSL 0.9.7/0.9.8,屡试不爽。GDB、valgrind一起祭上,确信了不是自己代码中内存管理的问题,而gdb的backtrace显示,出问题的函数乃是:BIO_copy_next_retry()。它的代码很简单:
void BIO_copy_next_retry(BIO *b)
{
BIO_set_flags(b,BIO_get_retry_flags(b->next_bio));
b->retry_reason=b->next_bio->retry_reason;
}
问题是,它没有判断b->next_bio是否为NULL!稍微搜索一下,发现03年底就有人问过类似问题,只是无人解答。折腾了很久,这个SIGSEGV如同幽灵一般如影随形。晚上躺在床上梳理建立连接的流程,百思不得其解为何它的next_bio是NULL,而PoC中写的代码几乎如出一辙,却没有这个问题,无论数据量的大小如何。几于绝望的时候却是灵光乍现的时候。当再次瞄了一眼BIO_copy_next_retry()的时候,我突然想到:虽然俺不能改这段代码,我可以在我的BIO chain中再append一个BIO嘛!这样它的bio_next就一定不是NULL啦!于是这个礼拜最出彩的一行诞生了:
sbio = BIO_push(sbio, BIO_new(BIO_f_null()));
在BIO_push(bbio, sbio)之前,我在sbio后添加了一个啥事都不做的BIO filter,于是这个BIO chain看起来是这样:
bbio -> sbio -> null
由于null这个BIO啥事都不做,对结果没什么影响。而正如我一直希望的那样,这次SIGSEGV终于消失了。
睁开眼睛,抬头看表,10:48pm。“哎呀,LP,明天的午餐还没做咧!”
– “我都做好啦!”
一骨碌从床上爬起,冲往厨房。果然,明天的午餐已经ready。心里那滋味,真的叫做“美好”。晚餐在浦东,和姑父喝了点酒。回来醉醺醺的倒头便睡。
曾经对恒仁路同济中学对面的一座古建筑很好奇,不知道其功用是什么。晚上路过的时候,阴森森的,没有半点灯光,树木、青藤的掩饰之下,夜晚看上去特别恐怖。白天往里面看去野草丛生,但建筑物的标识则半点都无。下午实在按捺不住,在google地球上搜了一把,终于知道,那座建筑原来是老上海图书馆,乃是国民党“大上海计划”标志性建筑的一部分。它现在应该隶属于同济中学,看这张图。不过现在已经废弃,篮球架已经不复存在。这里是稍近一点的图片。现在建筑上的字迹其实已经都被洗去。
参考: