2014年12月31日星期三

2014年年末座谈会

终:余,我们好像到早了呢,大哥二哥他们似乎还没到。
余:可茶点已经摆好了,是茉理姊姊放的吗?
终:那好,我先吃一个点心……
续:咳咳。
始:大家都到了,那么就开始吧。一年一度的竜堂家年末座谈会。
余:说是一年一度,可是感觉好像很久都没有召开过的样子了呢?
终:我来查一下……啊!上次是2004年。
续:今年是2014年。这么说来,上一次是十年之前了。作者也的确的是够懒的。
终:严正抗议!害我这么多年没有茶点吃。
始:听说作者也曾经为此深深自责过,不过最终还是脸皮战胜了羞愧。
余:我想作者也是有他自己的苦衷吧,我们还是不要太苛刻了。
终:什么苦衷,其实是懒吧!?我的茶点!抗议!
始:好了,终。天上一日,人间一年。对于我们而言,也不过就是十天而已嘛。我们还是进入正题吧。续?
续:嗯,今年发生了很多事情。不过就作者本人而言,他托我们向各位读者道个歉。因为Blog更新得实在不能算得上勤快。
终:我来数数,一、二、三……连这篇在内,2014年也就只写了15篇Blog。而且还有一篇是转载的。
续:基本上是一个月一篇的频率。所以呢,作者表示很惭愧,并且许诺会在新的年度里超过这个数字。
余:其实我看作者在今年六月份的时候还是蛮努力的。曾经有过三天内发表两篇Blog的记录呢。
终:我看看,6月1日,匪军……。大哥,“匪军”是什么?
续:匪军就是像你这样吃饭不给钱的混帐家伙。
终:我什么时候吃饭不给钱了?!
余:终哥哥,我记得好像是上次那个什么“大胃王”比赛……
终:噢,那个啊?哈哈!那是因为我最后赢了啊!赢了就不用给钱啊。胜者为王嘛。嘿嘿。
始:余,别听他的。“胜者为王”是低等动物的法则。
续:听到没?终,低等动物。
终:啊呸。
始:虽然是玩笑话,但事实也是这样的没错。看到有着悠久历史的中华民族如今堕落到与低等动物一个境界,大概连孔夫子也要哀叹吧。
余:说到孔夫子,好像也被匪军用来干坏事了。
终:咦……?
续:是那个什么“孔子学院”是吧?听说已经臭名远扬了。
始:好几个大学已经与其解除协议了。
终:等等……
始:这种做法的确很让人不齿。这种龌龊事情,恐怕即使是日本的无耻政客也做不出来。
余:听说控制这些的是一个女人?
始:没错,叫做许琳,是匪军下辖的所谓“汉办”的主任。听作者说以后打算用英文字母中正数第二个字母来称呼她。
续:……?
余:……?
始:怎么了?
余:续哥哥一定是在奇怪,终哥哥居然这次没有说“这女人看来最适合二哥您了”之类的话。
终:……为什么?说到“匪军”,连余似乎都一清二楚,而我却不知道?
余:终哥哥,你一定很久没有关注作者的Blog了。“匪军”就是指的中国共产党。
终:啊!我想起来了,就是把黄老关起来的那些人?
始:是的没错。而且被他们关进的监狱的,不只有黄老,还有许多别的人,都是出于类似的原因。
终:那末就是百分百的坏人没错了!
续:不过他们中间有许多自己人,最近也进去了。
终:真是活该!
始:因为匪军的头目最近在搞政治运动。每次政治运动都注定会有大清洗,这是历史规律。
余:而且听说我们上次去过的香港,也被匪军搞得乌烟瘴气,再也没有大不列颠统治时期的荣耀了。
终:这帮坏蛋。下次去中国内地的时候,我非好好教训他们不可。
始:终!人类的事情,我们不宜参与太多,静静看着就可以了。中国有句古话,叫“自作孽,不可活”。意思就是说多行不义必自毙。不管怎么说,人类自己的事情,要自己解决。
终:话虽这样说,可是……
始:续,下一个话题是……?
续:作者对明年的展望。
终:可恶,就这样岔开话题。
始:嗯,作者只是个小人物。所以,只要想好自己能做些什么就可以了。
终:报告大家一个好消息:作者明年又要加薪啦!
续:喂,可恶,被你抢先了。
始:呵呵,其实大家应该都已经猜到了。作者之前其实已经差不多算是透露过了。稍稍具体一点地说,明年作者可能要担任更重要的任务了。
余:就是传说中的“升职加薪”吗?
始:也不是,是“任务”不是“职务”哦,余。
续:简单地说,就是更累了。
终:这样啊?那明年座谈会是不是开不成了?如果开不成,今天的茶点我要双份。
始:那就从你压岁钱中扣,如何?金龙?
终:不好。那我还是不要了。
续:虽然明年可能会更累,但作者手下的“小弟”数量也会比今年多噢。
终:……所以?
续:所以,更新Blog比今年稍稍勤快一点,可能还是可以做到的。
余:不管怎么说,在这里要恭喜作者和他的家人了。
终:对了,作者也有一个和余一样可爱的小儿子呢。
续:目前才只有不到两岁而已。不过的确是很可爱。而且主要是没有被终欺负过。
终:我什么时候欺负过余?
续:怎么?我有说过你欺负过余吗?
余:没有。
终:你……你们……
始:哎呀,茶点已经被终吃完了,那么今天就到此为止吧。

(以上内容纯属虚构,并且与田中芳树无关)

2014年11月28日星期五

不喜欢,没有为什么

图片来自Google图片,与本文内容无关。

刚才看到Google+上有个PO说因为《三体》里面有政委,所以不喜欢。
具体内容不予评论,我只想说的是,不喜欢一个东西,只需要一个理由就足够了。你可以说出这东西有多么多么的好来,但我就一个理由,也许是很私人很难以理解的理由,但就是不喜欢,足够了。说再多也没用。

我没看过《三体》,也没有看的打算。虽然听到过很多的褒扬,我相信应该是的确有可取之处,也许是超越传统国产科幻小说的存在,但很奇怪,我就是没有兴趣。就好比不管谁跟我说红旗(牌小轿车)有多么多么好,而且就算它的确有多么多么的好,我就是不会去买它。

我是看叶永烈长大的人,当然,也看过郑渊洁。虽然我现在是个中共黑没错,但中国护照我也领,淘宝一号店京东什么的我也刷,海淘什么的我嫌麻烦还从来没去碰过。硬要说我崇洋媚外,我觉得自己也还没有那个资格。

有的人会说(嗯,我猜到他们会说):你连看都还没看过,就认为它不好看?
错了。我不是认为它不好看,我是不喜欢,没兴趣。Understand?

那到底是什么让我不喜欢?我自己也分析不太清楚,可能这涉及到很深层面的心理问题。也许是我不喜欢这个书名?也许是我觉得中国人的名字出现在西方绝对主导的作品体裁里很怪异?也许是习惯性地认为国产XX都那副尿性?也许是因为太多不应该喜欢科幻的人喜欢它所以我就觉得自己应该不喜欢它?

对了,我还不喜欢《货币战争》和《狼图腾》,也不喜欢《越狱》。这些,也都没有为什么。

2014年11月7日星期五

丢人现眼的脱口秀

上海台最近搞了一些脱口秀节目。舒悦,还有柏万青,都跑出来立在台上评论一些时事。——其实也不是最近,有一阵子了。公车上的移动电视还经常放,也经常性的让我听得想吐。前几天我又吐了一回,所以决定针对这个事情写篇Blog说一下。

对他们个人,我并没什么看法。舒悦在搞笑和扮老太太方面,真的是有一手的。柏万青呢,做调解的时候,能一眼看透矛盾的关键所在,的确厉害。这些都是让我极为佩服的本事。但是,人不可能全能。硬要捞过界,做自己原本并不擅长的事情,就得做好丢人现眼的打算。比如这两位跑去评论时事。

我觉得吧,舒悦大概是真的见识不够。一个搞传统戏曲艺术的,人生阅历又没到位,实在是讲不出啥好道理,只好拿些言语哄老阿姨开心,也是情理之中的事情。柏万青呢,本来以她的能力应该能拎得清,奈何屁股决定脑袋,老是容易把自己当政府,于是也经常讲出些让人摇头的话来。

比如他们经常拿来开涮的“上网有害论”。某某女孩被网友骗财骗色啦,某某小伙子被网友骗去做传销啦,某某X年网购上当受骗啦,某某大学生开设色情网站被抓啦……,等等等等,大约都是这之类的话题,然后一副“网上那些乱七八糟的东西”的口吻,以及拿“网上的东西好相信伐”当口头禅。反正就是“网络不是个好东西”。

其实这种事情都不需要我来吐槽。网络只不过是通信的一种方式而已。没网络以前有电话,没电话以前还有面基。网络只是让沟通联系更容易而已。会上当受骗的,倒退几百年,没网没电没石油,一样会上当受骗。跟网络搭什么界?

更何况,网络如果真能让信息来去更方便,其实反倒是会让人更不容易上当受骗才对。以前那种不开化的年代,同一个骗局可以全国各地翻来覆去随便骗,现在上Google搜一下你就能知道刚才那个骗子电话到底是怎么个玩法。在阿加莎·克里斯蒂那个年代,伪造身份冒名顶替连波洛都能差点骗过去。现在不要说冒名顶替,就是你想隐姓埋名,也分分钟给你人肉出来。不是网络上的东西不好相信,实在是有些人缺心眼儿。为什么缺心眼儿?怪爹怪妈怪政府呗!

能说出那些混帐逻辑,可见这些脱口秀的主持人实在是不合适去评论时事。脑子早就跟不上时代了,硬要去评,那不是丢人现眼么?

2014年11月6日星期四

对GAE Proxy的个人看法

GoAgent的作者,+Phus Lu,近日表达了对GAE Proxy翻墙的一些悲观的看法,并表示要努力肉翻。肉不肉翻本文不关心,但是对于GAE Proxy翻墙,想顺便说上几句。

其实,翻墙手段林林种种,说到底,无非就是两类:Hack/Proxy。

所谓Hack,就是指那种针对GFW的封锁手段,进行技术上的破解,使其对正常的Internet活动的干扰失效的办法。最典型的如hosts:你要破坏DNS查询?那好,我不查就是了。还有西厢计划:你要干扰我的TCP握手?那我想办法扰乱你的判断,欺骗你。这个有点迎着刀锋上的意思(我喜欢),不过得看对方刀法有没有破绽。有,当然可以利用;没有的话,就没辙了。

而Proxy,则是“找朋友帮忙”的想法。你把Twitter的IP全给封了对不对?我另外找台境外的代理服务器,帮我搭个桥,我跟代理之间说暗语(加密),你就傻眼了对不对?这种翻墙方式依赖于第三方,基本上是“避其锋芒”的做法,倒是比较有利于商业化。逻辑上,依赖于“土共为了经济不敢把外网全部封了”这个假设。的确,只要GFW不开白名单,路子嘛总是有的。

可见,以上两类翻墙手段,各有优点,也各有弱点。GAE Proxy,顾名思义,属于后者。
简单地说,Google提供了个免费的云计算服务,可以在上面跑Python服务端脚本,而且支持urlfetch。如果在本机上写个程序,把HTTP请求“改头换面”(加密)之后发给在GAE上的那个Python脚本,让它通过urlfetch代为访问目标网站,就能够躲过GFW施加的诸多干扰。
这个典型的Proxy方案有两个关键点:

  • 加密后的HTTP数据能不能瞒过GFW?
  • 本机能不能访问GAE Proxy?

如果这两个关键节点能够得到保障,后面就一马平川了。

第一个问题是个技术问题,比较容易解决。反正客户端和服务端都是自己做的,想怎么加密都可以。但第二个问题就比较麻烦了。Google树大招风,而且早就不受GFW及其背后主子的待见。封端口、封IP、封证书,都是GFW现在就完全可以采取的成熟手段。事实上,我还很有一点惊讶于为什么GFW目前还没把Google的可用IP给封完?

我相信,+Phus Lu的悲观,也来自于此。尽管目前Google还有一些IP可以用来访问,但我们心里都很清楚,真要封起来,那也就封了,谁也没什么招。Proxy玩的是“躲着走”的路数,一旦公开高调宣传,基本上就是跟hosts一样见光死。私人的Proxy,虽然已经很低调,尚且还经常被流量统计和行为模式识别给干掉,更不用说全球知名的Google。悲观,是很自然的事情。

※    ※    ※    ※    ※    ※    ※    ※

但是,我还是觉得,GAE Proxy仍然会是我在白名单或Google的IP全部失效之前的重要翻墙手段。有一个不太重要但又有点意思的理由。原因跟Google的弱点一样:它太知名了,用的人太多了。

这里要先解释一下一个看起来不太相关的问题:你们知道为什么有些人就算使用了境外的代理/跳板/VPN,仍然被当局给抓住了吗?

找境外的代理服务器要日志,人家不见得会给你,而且那台代理说不定只是一台肉鸡而已。但是为什么当局能追查到了用代理的人呢?答案很简单:查路由。路由器在当局手里,结合时间一查谁在当时路由到了这台代理上,情况就很清楚了。要对付这种情况,一般是需要境外的多级跳板才行。普通人哪来那么多的境外跳板?再说,级数一多,速度也就慢了。不是专业黑客,一般做不到这一点。

但是,GAE Proxy天生就是一个多级跳板。你并不清楚你的Req发到GAE Proxy了之后,中间又经过了几跳,才从Google的集群中出去,到达了Dest。对于当局而言,查路由没啥用。从Dest上看,只知道是GAE的云当中伸了一只手出来干了这个事情。至于是谁?GAE Proxy的IP,其实就是Google那一堆hosts地址中的某一个。同一时间,太多人在用,而且还全是短连接,呵呵……。如果你再注意一下自己的行为模式不要太容易地被识别出来,就算是当局也不容易知道干这个的人是不是你。没错,GAE肯定有日志,但Google会给某当局吗?这难度至少比去电信调路由日志要高上好多好多。你要做的只是通过两步验证之类的事情把自己的账号安全保护好,就行了。

当然,对隐秘性有高要求的人,应该去用Tor。不过我觉得,并不是一定要干什么惊天动地的“坏事”才需要隐秘行事。很多时候,你不经意的一些行为,日后都可能会成为麻烦。可能有的人觉得现在还没有到那种程度,但是我想没有人会否认苗头已经不太对了。如果真的到了《1984》那种时候,可能你几十年前去看过的一篇抒情散文都会变成“罪证”。文革的时候,这种事情并不是没有过。谁能确保21世纪不会再来一次?

不管怎么说,给作恶的当局添上一点麻烦这种事情,我还是很乐意去做的。

2014年10月31日星期五

SingleThread下遇到的并发问题

手下某个小弟,有一天报告我说他写的某个Win32 Application有一个奇怪的Bug,搞了半天搞不定,向我寻求支援。Bug现象是:下载文件,完毕弹框提示,点掉之后报错,Crash。

通常而言,这种问题,往往是因为在释放、删除什么东西的时候,该做的事情没做对,比如对着一个对象的指针进行了重复delete之类。但看了下代码,没觉得这方面有什么问题。因为这是个SingleThread的程序,于是尝试用单步跟踪跟了一下,发现有一段代码似乎在所属对象析构之后还在跑。这就有点奇怪了:SingleThread的Application,不应该有这种属于MultiThread的毛病才对。Socket模型用的是AsyncSelect,也就是说“异步”是用Windows消息做出来的,并不是真的“并发”。那么到底是哪里不对劲呢?

再接下来分析发现,虽然是SingleThread,但最后出错前弹的那个提示框,是在OnReceive的时候通过SendMessage去弹的。这样就有眉目了:ModalDialog并不阻塞ParentWindow的消息循环,所以在弹框等待用户确认的时候,消息循环收到了OnClose,于是Socket对象在用户点击确认按钮之前,其实已经被Destroy了。之前还没跑完的OnReceive,接着再跑的话,当然只能Crash了。

分析到这里,问题就已经很明白了:这就跟MultiThread下临界区没加锁一样嘛。你以为SingleThread下每个函数就都是原子操作,不会被乱入的东西打搅?呵呵,你一DoModal就会给你再嵌个消息循环进去的。可怜很多小弟连DoModel的原理都没搞懂就开始写程序了。我上次还听几个小弟在争论相关问题呢。不是说写程序必须啥都弄明白才能开始,但若是只拎半壶水就开跑,将来就难免会碰上这种“奇怪”的问题。

要修正这个问题,也很简单,改成用PostMessage让MainWindow自己去处理弹框的事情就可以了。不过有点奇怪的是,在XP下好像不会看到错误现象。Win7下直接运行EXE也不报错。只有通过两层以上的CreateProcess去调用,才会看到现象。难怪没什么用户报告这个问题。是不是OS觉得这个EXE反正会很快地Over掉,有些错误就不报算了?看来微软在私底下还是有一些没告诉大家的小动作的哈哈。

总结一下,这个案例教育我们:

  1. 不要以为只要是SingleThread就一定不会遇到并发问题。
  2. 前/后台逻辑应该要区分清晰,是后台代码就别抢前台的活儿。
  3. 还有,SendMessage/PostMessage不要不经大脑就乱用。

2014年10月21日星期二

[转载]方舟子:周小平梦游美利坚

摘要 : 周小平只是在梦里游了趟美国,然后就开始信口开河控诉起美国的罪恶。他的这些胡言乱语,有的需要有在美国生活过的经验才能识破,有的则根本不需要,只要上网一查就知真假。
孤陋寡闻,我最近才听说冒出了一个“网络作家”代表周小平。既然是“网络作家”,好歹得有作品,搜了一下,无非也就是写了一些博客文章,这就成作家了?现在作家门槛可真够低的。
此人有两篇博文引起我的注意。2010年9月肖传国因雇凶袭击我被抓获后,周小平写了一篇《当世上没有方舟子,天下就和谐了。》,大骂我对唐骏、肖传国搞“学术敲诈”,是“无赖”,义正词严地宣布:“历史终将证明:我们这个社会需要的不是方舟子,而是尽可能地少一些这样的无赖。立此为据。”难怪清华大学肖鹰教授说:“今日中国文化三个代表——拜金文化代表郭敬明,骗子文化代表韩寒,流氓文化代表周小平。”
另一篇是今天在微信上看到有人在传周小平的一篇宏文《梦碎美利坚》(http://www.dangjian.cn/jrrd/wptx/201409/t20140919_2188807.shtml),里面列举的关于美国的种种不是,几乎全是他胡思乱想捏造出来的。他这是梦游美利坚吧?我们就来看看他是怎么梦游的。
【周小平:美国很多城市的服务业工作者薪资在三到五美元之间】
自2009年7月以来,美国联邦最低工资是每小时7.25元,只有两个州最低工资比这个低,是每小时5.15美元。周小平在梦里发现了美国哪所城市的服务业工作者薪资在三到五美元之间?
【周小平:还有很多人在网上大肆吹嘘说美国的房子是永久产权,但是这些人却总是忽略在美国买房后的一项重要开支:那就是不动产税。美国有一个专门从事房屋估价的官方办事机构每年要来为你的房子做价格评估,所以你要交多少税,不是按你购买房子时的实际成交价,而是按现在的价格来进行评估的。所以哪怕你买房的时候是50万,但如今房价涨了5倍,你就得按250万美元的估价交税,这样一来,几年税金就抵得上你当年的购房款了。】
美国并不是所有的州的不动产税每年都重新做评估的,有的州的不动产税就是按房子时的实际成交价来算的,不管房价怎么涨,都是一样的税。例如加州就是如此。
【周小平:而且就算你买的房子没涨价,你也得按房子总价的2.5%交税,再加上物业费和社区管理费用,你买套房子住上30年,光是你要交的这些税就够再买一套一模一样的房子了。而且一旦你交不起这些税,房子就会被银行收走并拿去拍卖抵债。也就是说:美国的房子实际产权只有30年,而中国的是70年。】
美国不动产税税率由地方政府决定,不同的郡、城市、社区都不一样,并没有一个固定的税率。全美国平均税率是1.04%,税率最高的新泽西州平均为房子总价的1.89%,税率最低的路易斯安那州平均为房子总价的0.18%。(http://taxfoundation.org/article/property-taxes-owner-occupied-housing-state-2004-2009)周小平在梦里见到了美国房主都要按高达房子总价的2.5%交税?
如果交不起不动产税,房子会被政府拿去拍卖,而不是被银行收走。这里没有银行什么事。难道周小平把不动产税当成了购房贷款?
交不动产税不是白交,而是享受当地公共服务的支出,因为不动产税用于当地社区基础设施建设,特别是公共学校建设。所以一个社区的不动产税越多,当地公共学校就越好,公共学校越好,带动了房子涨价,收取的不动产税就越多。这就是为什么在美国买房子很看重学区的原因。
至于周小平把交了多少年不动产税等于房价当成该房子的实际产权年限,这种流氓逻辑,不值一驳。按周小平的说法,美国的房子实际产权只有30年,住了30年就没产权了,有人住了几十年房子怎么没被收走?继续再交30年的税是不是还倒贴了一套房?
【周小平:除了经常有人在网上吹嘘美国房价便宜之外,我还经常在网上看见大量的谣传说:“美国3万美元可以买宝马, Z4跑车报价才29888美元。”等等,但实际上这点钱在美国,连个二手宝马都买不到。】
去美国宝马官方网站查一下就可以知道这是不是谣传。2015年款BMW X1 sDRIVE28i的官方报价是$30900 (http://www.bmwusa.com/standard/content/vehicles/2015/x1/sdrive28i/default.aspx),实际卖价当然比这低(美国买新车可以砍价)。
【周小平:美国本土生产的国产低端车,零售价都在3万美元左右,而中国似乎也有不少价格在3万-5万人民币的国产低端车。】
实际上美国本土生产的国产低端车的零售价不到1万5千美元。例如2015年款福特FEISTA,它最低配制的官方报价是$13865。(http://www.ford.com/cars/fiesta/
【周小平:美国的汽车保险和维修费用惊人,交强险一年要3500美元,修车换个闸皮就要400美元左右,这还是低端车的维修价格,如果是中高档汽车就更离谱了。换个雨刮器,做个保养都要几千美元。】
美国汽车保险各地变化很大,2014年美国汽车全包保险的平均缴费是1503美元。(http://www.insure.com/car-insurance/car-insurance-rates.html)如果是强险(出事时保别人不保自己)则要比这低得多。周小平又是梦游到美国交了3500美元强险。
至于周小平列举的美国汽车维修费高得如此惊人,做个保养都要几千美元足以买一辆很新的二手车,我只能说他是在梦游时遇到黑店了。
【美国高速公路都是收费的,只是收得不贵而已,但这些收费不贵的高速公路的条件和中国的省道质量是差不多的,裂纹和坑洼遍地,相当毁车。除了高速收费之外,过大桥也是要收费的,而且大城市进城还需要交进城费10美元左右。】
美国高速公路有收费的,但大部分是不收费的,比如加州的高速公路除了个别路线和快速道,都是不收费的。我在美国加州开了那么多年车,还从来没在高速公路上交过费。周小平是不是要说加州的高速公路都和中国的省道质量差不多?过桥费有,进城费没听说过,是周小平在梦里发明的?
【实际上网民只要打开ebay网络就不难发现现在美国的iPhone裸机销售价格800美元左右,而中国淘宝iPhone的价额则在400美元左右,到底谁便宜呢?】
从苹果官网可知,16GB版iphone6裸机在美国售价$649,中国售价是5288元,到底谁便宜呢?
【美国的酒店也酒店很贵,大城市在160美元-200美元一晚,小城市在100美元一晚,而且100美元的那种基本不能住,十分脏乱差,条件相当于中国内地40元一晚的小旅店。】
美国最便宜的酒店是汽车酒店,一晚40美元左右。一晚100美元在很多城市可以住假日酒店这个档次的了,周小平是不是认为假日酒店“十分脏乱差,条件相当于中国内地40元一晚的小旅店”?
【美国的教育问题也是很奇葩的,虽然美国实行的是从小学到高中十一年义务教育,中国是从小学到初中九年义务教育,看起来比中国好。但问题是谁敢把自己小孩送去美国的公立学校念书呢?大部分美国公立学校的高中毕业率只有30%-50%,很多学生上了大学之后在碰到13×2=?这样的数学题时都还得依赖计算器。】
美国实行的是从幼儿园到十二年级的十三年义务教育,称为K-12。美国85%的小孩上的是公立学校。周小平的意思是美国85%的父母大胆包天?2012年美国高中生退学的比例是7%(http://nces.ed.gov/fastfacts/display.asp?id=16),周小平要发明一门什么样的数学方法才能据此算出大部分美国公立学校的高中毕业率只有30%-50%?
【美国的富人则根本不会把自己的孩子送入这种所谓崇尚“散养”的学校,他们都会把自己子女送入教育及其严格的“私立学校”“教会学校”等等。而要上这些学校,除了要购买学校附近的超高价学区房之外还需要有人给你开关系递条子(推荐信制度),否则想都不要想。】
美国私立学校并不划学区,公立学校才划学区,要上好的公立学校才需要购买学区房,可见周小平根本不知道私立学校是怎么回事。
【美国的私立学校有多贵?我们可以举例说明,美国排名前二十的大学,四年下来光学费都得25万美元以上,还不包括住宿和生活所需费用,因此大多数普通美国人都负担不起。想申请到奖学金非常困难,想问银行贷这么多钱也非常困难,如果你是普通人家的孩子,想要有人给你递条子(推荐信)根本就是痴心妄想。】
在美国,如果你是普通人家的孩子,被名牌大学录取,不用担心交不起学费。例如斯坦福大学是根据家庭收入的多少收取学费的,家庭年收入低于10万美元的学生学费全免,家庭年收入低于6万美元的学生则连住宿费都免了。(http://financialaid.stanford.edu)周小平一开头就自己说美国人的人均年薪约为三万五千美元,那也就是说,对大多数普通美国人来说,如果他们的小孩能考上斯坦福,都不用交学费了,还担心什么负担不起?按斯坦福的官方说法,70%的学生都能获得资助。周小平以为写推荐信是多么困难的事,说普通人家的孩子根本就是痴心妄想,他以为那是中国呢?我认识的一个普通华人家庭的子弟,为了上西点军校就找了国会议员给写了推荐信。
【在吃的问题上,美国人的现状也十分堪忧。民以食为天,很多美国人中午都是自己带饭吃的。两片面包夹一片火腿一片芝士一片西红柿两片生菜叶子,就是一顿饭。美国人为什么吃得如此节约呢?除了他们的味蕾不发达之。繁重的小费负担也是一个重要原因。在美国吃饭一般要强制收取用餐价格15%-20%的消费,不能不给的。所以即便去吃一顿路边小餐厅人均消费也在20美元-40美元,所以很少有人去,中午一般就直接带个汉堡或者三明治就解决问题了,而且天天如此,顿顿如此。】
小费一般是按惯例自愿给的,是对别人服务的欣赏,不给或给得少显得没品,并不是“强制收取”“不能不给”。人均消费20美元-40美元的算得上服务不错的中档餐厅了,如果是吃快餐或自助餐,用不了那么多钱也不必给小费。午饭时间一般也就一个小时,不是自己带饭就是去单位的自助餐厅吃,谁有那么多时间在上班时专门跑外面的餐馆吃午饭?周小平还以为是美国人吃不起怕付小费呢。
周小平只是在梦里游了趟美国,然后就开始信口开河控诉起美国的罪恶。他的这些胡言乱语,有的需要有在美国生活过的经验才能识破,有的则根本不需要,只要上网一查就知真假。这个“网络作家”连美国汽车价格、iPhone裸机销售价格之类很容易上网查明的事实都敢胡说,是把网民全当成像当官的那样容易糊弄吗?
2014.10.20.

2014年9月29日星期一

做一只愤怒的China猪

香港的抗争已经到了催泪弹和橡皮子弹的程度,墙内众人还在讨论买汽车/火车票和去哪个景区排长队。
Instagram被封,我不知道有多少人用这个貌似小清新的玩意儿。也许小众,也许不少。但是一点可以肯定,墙内众人一定会认为是“服务器出了问题”。于是香港的问题,也就只有外媒会关注了。
也许,我们是不觉得自己缺了什么,因为那作为“人”的权利,从来不曾有过。我们是被豢养的猪,吃饭、喝水、睡觉、纳税。

我经常替猪辩护,论调大概是这样:并不是不关心,只是来自坦克的压力比较大。各自心里都敞亮得很。厨房饭桌上见真章。
我不觉得自己很傻。明白人也许是有,也许不少。他们混在猪里面,只是一种保护自己的必要。——我相信是这样,因为我看起来还相信世界有着美好的一面。这可能是因为我还不够强大,需要这么一种说法来支撑我自己的信念。如果有朝一日发现所有的猪真的都只是猪,那我会不会想腰上绑点什么去自杀?

有一种说法:一切痛苦,都来自于对自己无能的愤怒。那么,一切美好,也就来自于对自己无能的忘却?或者是让自己变得有能。两种皆可。在这个层面上,我觉得没谁应该被责怪。既然不敢做死人,那就做只猪活着吧。做一只愤怒的China猪。

2014年8月2日星期六

不能只听你一人儿讲闲话吧?

这次温州的事情挺好玩的。我也没啥好评论的(虽然槽点很多),各位自己看吧:


以下内容来自大多数看得到温州电视台节目的广大市民们看不到的比百度“百科”稍微要权威一点的维基百科王炳章词条(Blogger编辑器的HTML复制功能还是不错哈):


王炳章[编辑]

王炳章(1948年),出生于中国河北省石家庄市基督教徒,美国永久居民,中国民主运动政治家,现在狱中。

生平[编辑]

幼年移居北京,在北京完成小学与中学教育。
1979年,他留学加拿大麦吉尔大学医学院攻读博士学位。1982年,他获加拿大麦吉尔大学医学院医学哲学博士学位,为中华人民共和国建国后公费留学生在北美获得博士学位的第一人。同年,创办海外民运刊物《中国之春》。12月1日,蒋经国函电宋美龄
“关于王炳章‘中国之春’举动,我方早有联络,正进一步了解情况,并希望端其方向朝民族大义正确途径发展。”[1]
1983年,王炳章创建海外第一个民运组织“中国民主团结联盟”,担任第一、二届主席。1989年,他参与创建中国自由民主党,担任第二届主席。1998年1月,他潜入中国大陆推动筹组民主活动,二周后被中共逮捕并驱逐出境。1998年2月,他参与创建中国民主正义党,出任发言人和中国民主运动干部学校理事会顾问。6月,他出任中国民主党海外筹备委员会和工作委员会顾问委员。2000年2月,他出任中国民主党海外总部顾问。
2002年6月,王炳章在越南边境附近,遭绑架至一艘往中国的船上,在中国领土上遭公安逮捕。2003年2月,广东省深圳市中级人民法院以为台湾从事间谍活动和组织领导恐怖组织的罪名判处王炳章无期徒刑,他目前正在韶关北江监狱服刑。一直以来都被狱方单独关押,禁止任何人与他交流,目前他已经中风多次。狱方的看管人员也是六个月一换。
2013年,台湾立法委员田秋堇中华民国国家安全局质询此事,国安局公开回复,从未运用大陆人士王炳章及彭明先生从事情报工作。

家庭[编辑]

其妻为台湾人,两人在美国结婚。生有一女,王天安。

著作[编辑]

《中国民主革命之路——中国民主化运动百题问答》,原名《民运手册》,出版于1998年,以问答的形式解答关于民主理念、民运策略、改良还是革命等问题。有两大特点:其一,是运用通俗的事例,将高深的民主理论浅显地表达出来,具有初中程度的人即可读懂。其二,对民主化运动的实际运作有翔实的介绍,有较强的实用性。[1]

评价[编辑]

  • 2003年2月王炳章被判刑的同月,龙纬汶柳玉成伍国雄等人成立“各地营救王炳章大联盟”,争取王炳章尽快获释。
  • 尽管王炳章博士是中国海外民主运动的先驱,并连续担任过多个海外民运团体的最高领导人,但王炳章首先是一名基督徒,按照基督徒的信仰与处世原则,王炳章博士多次冒着自由和生命的危险闯关回国从事政治活动。

参考[编辑]

  1. ^ 周美华萧李居编,《蒋经国书信集——与宋美龄往来函电》(下),台北国史馆出版,2009年,第335-336页。

外部链接[编辑]

2014年7月31日星期四

Alipaybsm.exe是个有意思的东西

在接下来的篇幅中,我要讲一个目前还没结束的故事。故事可能还会继续发展下去,也可能因为我的懒而就此打住。但至少我觉得目前已经有足够有意思的信息可以让诸位知道了。这件事,跟支付宝有关,跟(网络)信息安全也可能有一些关系。有兴趣的朋友,可以接着看下去。


我以前曾写过一个服务器Ping值测试程序(参见这里《写了个批量测试服务器Ping值的小工具》)。这个程序一直都能满足我的需要,直到有一天在我老婆的笔记本Win7 x64系统上遇到了问题:对几乎所有的IP,我这个程序的Ping都很快收到了回应,快得不正常,几乎就像做了个本地调用一样,与实际情况不相符。于是我打算看看这是怎么回事情。

当时我人在公司,VC6远程调试又不方便。最后靠着DbgView终于搞清楚了:接收到的数据中,多出来了一份不正常的东西。我之前的代码,并没有估计到这份不正常的数据可能会出现,所以处理上出了些问题。

OK,这算是我的Bug。可这“不正常的数据”到底是什么东西?我把它Dump出来一看,还真是有点奇怪!ICMP Type是8,源地址和目的地址则与预期的Echo回应包刚好相反。算上sendto时候系统自己加上的IP包的包头,跟我送去发送缓冲区里的数据那是一模一样。

要解决我程序里的这个问题非常简单。但是另一个问题就不那么好回答了:为什么其它电脑上不会这样,偏偏这台电脑会出现这种奇怪的事情?
直接答案很简单——它一定跟别的电脑有什么地方不一样!
那么还有第二个问题:到底是什么地方不一样呢?

可以说是我的幸运,也可以说是阿里集团的不幸。因为我的Taskmgr里面进程列表设置为按ASCII字母序排升序的缘故,我很快就找到了这第二个问题的答案:Alipaybsm.exe。杀掉Alipaybsm.exe这个进程,前面提到的那份“不正常的数据”就不再出现。而这个Alipaybsm.exe似乎由AlipaySecSvc.exe在守护,过了一会儿就又自己启动起来了。它一出现在进程列表中,我一试,哈,那个奇怪的现象就又出现了。

后来,我把这事情在Twitter上说了一下,还引发了一场小小的讨论。
我目前还没完全想明白Alipaybsm.exe这样做的目的是什么。初步感觉,有可能是跟背地里监控网络流量有关。毕竟,目的地址不正确的数据,就算被放入Socket接收缓冲里面,在网络层与传输层之间估计也被滤掉了。我这次是因为用了SOCK_RAW,需要自己下到网络(IP)层来处理数据,才碰巧发现了这个情况。如果只是在传输层(TCP/UDP)从事工作,估计不会有任何察觉。
只不过,反过来讲,如果能做到复制数据到Socket接收缓冲,那应该完全可以做到监控流量而不带任何痕迹才对。所以我目前还只能理解为,Alipaybsm.exe想完全监控网络流量,所以利用了这个手段(复制发送的数据到接收缓冲中),但干这事屁股没擦干净(也可能没法擦干净),才产生了我遇到的这些情况。

我本来以为当时那个Alipaybsm.exe是个假货。但看EXE的详细信息,以及绑定的数字证书,都像是支付宝官方的真货。我又以为那只是一个不成熟的版本,可能有Bug,但我前两天为了转一笔账,又去下载并安装了一个支付宝安全控件,然后它又出现了,带着它那奇怪的行为又出现了。
所以,我们来仔细看看这货吧:

看上去挺正常吧?

在Twitter上讨论的时候,有人表示,在Mac上用防火墙没观察到有这个现象。为此,我今天特意去确认了一下:在Windows上抓包,也观察不到这个现象。我估计,只有自己写基于SOCK_RAW的程序,才能收到这些数据。为了检查这种特殊的行为,我专门写了个小程序AlipaybsmTester,基本上就是一个单地址单次单线程的PingTester。

从这幅截图中可以看到,Microsoft Network Monitor只抓到了一来一回共两个包,但我的测试程序发了一个包收到了两个,内容各不相同。如果杀掉Alipaybsm.exe,那就只会收到后一个包了。

接下来再看看这个Alipaybsm.exe的一些更好玩的事情:
很奇怪的是,它其实并不是随着“支付宝安全控件”(Aliedit.exe)装上去的。当你登录支付宝,根据Web页面上的提示安装了“支付宝安全控件”时,只会在Program Files (x86)\alipay下面建一个名字叫alieditplus的目录。

但是过一会儿(我这次过了30分钟左右),在alieditplus下面会出现一个update目录,并下载一个SafeTransaction_Setup.exe放在其“\job\file\tmp\zip_1009_”子目录中(不同时期不同环境中路径可能会有所不同)。随后Program Files (x86)\alipay\SafeTransaction目录便出现,里面就有Alipaybsm.exe(当然还有一些别的)。

我在网上想搜一下关于这个Alipaybsm.exe或SafeTransaction_Setup.exe的相关信息,发现少得可怜。Alipay官方完全没有提到过这些东西,好像它们是感染了AIDS的私生子一样。不过每个安装了支付宝安全控件的电脑上,估计都会有这些个东西(还有个AlipayDHC也值得注意)。我认为以这种方式进行推广的程序,很可能另有其目的,不见得真的是保障个浏览器安全这么简单。如果真是为了保障浏览器安全,完全可以公开(乃至大张旗鼓地)宣传,然后打包到安装包里一起分发下去正大光明地安装,不是吗?

PS: 我后来发现,杀掉AlipaySecSvc.exe也会导致复制数据包的现象中断,并且重启该服务之后,恢复现象花的时间比单单杀掉Alipaybsm.exe要长。可见Alipaybsm.exe的角色大概只是一个行动的发起者和结果的分析者,具体对流量实施监控的行为,很可能是它去调用AlipaySecSvc.exe中的某些个服务来完成的。这说明对于“支付宝安全控件”本身也不能掉以轻心。相关功能其实可能一直就放在AlipaySecSvc.exe中,只是没有人来扣扳机而已。而这个扣扳机的可以是Alipaybsm.exe,也可以是别的谁,那谁谁谁。

2014年6月11日星期三

荒野求生:验证hosts可用IP的方法

最近GFW喝了红牛,大家翻墙都遇到一些问题。常用的Google服务器IP几乎被封完。于是乎,寻找hosts可用的IP,就成了一件日常工作。

找IP,有很多种办法。八仙过海,各显神通。其实找IP并不难,特别是在有些二逼把Google的IP地址列表像性病广告一样满大街乱贴的情况下。但是,找到一个“据说可用”的IP地址,并不代表它真正可用。它有可能已经被封了,有可能用起来很慢很卡,也有可能是一个过期的IP地址,Google已经把它拿去干别的事情了。那么,如何确认一个IP地址是否可用?

大致而言,要确认一个IP地址是否“可用”,一般有以下的方法/步骤可以遵循:

  1. ping一下,看看延迟多少:Google服务器基本上都会响应echo,所以如果ping不通的话,很可能就是被IP黑洞了。即使能ping通,但延迟要是很高,而且有丢包情况的话,这个IP的可用性也要打一些折扣。
  2. telnet测试443端口是否可以连通:如果443端口被封,那对这个IP也就不要有什么想法了。如果连通了之后立刻断开,或者是一旦有任何输入就马上断开。那么说明这个IP地址被GFW牢牢盯住。任何的连接企图可能都是白费力气。还是忽略它吧。
  3. 用Web浏览器查看服务器证书:443端口可以访问,只说明这个IP开通了HTTPS服务。但到底是不是Google服务器?还得连上去看一看。浏览器一般会提示证书不匹配。不要紧,因为我们此时是用IP地址直接访问的。恐怕不会有什么证书是颁发给IP地址的吧?我们只要看到证书是颁发给*.google.com或google.com的,就可以了。忽略掉浏览器的警告,应该就可以进入Google的搜索主页。但如果证书是给*.googlevideo.com的,那就算了吧。这个不能用来作hosts,也不能跑GAE Proxy(如GoAgent)。
  4. 在五分钟内多次访问这个IP的HTTPS服务:如我之前的博文所言:GFW对于某些地址段,启用了“按证书盯防”的策略。它会在你访问Google服务器的443端口时,也去尝试访问一下,然后检查拿到的SSL证书。如果发现是*.google.com或google.com,那就(临时)封掉。但这个策略是由一个异步模块完成的,所以封锁行为不会立即生效,大概会过上几十秒至一、两分钟。如果这个IP的证书真的被GFW“盯防”,那你用来作hosts也只能用上一会会儿而已,岂不是很不爽?所以,就算你很激动,也要耐心等上五分钟。如果五分钟后该IP地址仍然可用,那么恭喜你!You got it!

2014年6月3日星期二

匪军六三新动向

昨天呆在家里陪老婆儿子,没有怎么上网。本以为凭着头一天找到的十几个Google服务器可用IP,撑过六四绰绰有余。谁知道看到的情况大不同。

公司是双线出口,电信和联通各一条线,路由规则没有绑定,所以随时可能发生变化。电信这边还好,联通那边问题就大了。有一些IP根本就ping不通了,另外一些丢包率也很可观。我手头上十数个IP,在电信和联通两边都可用者,寥寥无几。而且过了一会儿,情况似乎愈发恶化了,可用的IP也很快变得不可用了。难道GFW开了“全场盯防”?

所幸,有一些IP,看似被封,过了一会儿又可以用了。而且一般还能用上个十几二十分钟。手上IP多,终归是有一些处于可用状态。到了下午,形势慢慢明朗了,我觉得我差不多摸清对方的路数了,但是却很奇怪。

乍一看,似乎还是六一的模式:跟着HTTPS请求去识别服务器证书,然后对于*.google.com进行异步的TCP端口屏蔽。但至少在联通这条线路上,屏蔽的方式有时候是IP黑洞(ping不通),有时候是TCP端口屏蔽。封锁的时间也是长短不一、先后不一。有时候很快就被封了,紧接着下一个IP却又可以用上好一段时间。说是GFW负载太高似乎也不合适。我随后提出了一种假设:
ISP(其实就是GFW的接入责任方)为了应对六月头上这几天的紧急事态,调动了一批人来对流量做人肉监控。它们会把HTTPS访问给记录下来,让审查员去人工判断是否需要封锁。如果需要,那么提交给GFW去封锁。
封锁的办法,很可能是向路由器/防火墙中添加动态IP规则。因为如果添加静态规则,那么需要节点重启才能生效,那样效率太低,网络波动也太厉害。但是动态IP规则可能是一个很消耗资源的东西。要灵活,就得付出代价。我估计如果添加太多规则的话,所有IP包的转发效率都会受影响,所以规则数量只能限制在一定范围之内。所以我观察到一个现象:被封的IP,过一会儿就会重新可用。在下午的一段时间内,我差不多用4个IP就可以做到轮换。封了1个就马上去检查另外3个,总有一个是可用的。

还有一个现象也很值得玩味:我用的这4个IP都是同一个C段的地址。如果GFW聪明的话,直接把我这个C封掉就一了百了。但它不。这说明要么是机器在干活,要么就是一些工作在很低的层次,彼此信息相对隔绝的审查员所为。有可能明天一早能发现这个C被封了,那就说明他们开过会了。

另外,有一段时间,一些国内的IP地址,在联通线路上也被封过。比如ipseeker.cn对应的61.142.238.91,比如国内的一台DNS服务器114.114.114.114,还比如招行的网银专业版用到的site.cmbchina.com:443。目前看来除了GFW暴走没有其它的解释。因为随着下午四点之后GFW暂时歇菜,这些国内IP也都恢复了正常(特别是ipseeker.cn那个)。为什么封国内IP?我估计是因为GFW按ISP架设,不同ISP、不同地区之间的屏蔽措施都有所差异。如果抓住其中的松紧尺度做文章,架国内代理绕开GFW并非不可能。

有人说下班,也有人说去吃饭了。不管怎么说,下午四点之后,GFW似乎从疯狂中恢复到了六一时的状态。明天就是所谓的“大考”。我也趁今天这个准战争状态再度改进了一下手中的工具。咱们就明天见真章吧!别没品位地拔线或白名单哦!

2014年6月1日星期日

匪军六一新动向

六一懒觉睡了起来,发现刚启用的台湾hosts不能用了。试了一下手头上这些年积攒的hosts,一夜之间几乎全部失效。ping可以通,延迟也没有改变,但80和443端口都被封,——GFW又搞新花样啦。

其实也不是什么新花样,充其量只是把手段多使了几招而已。不过这回似乎有一些不太一样的地方:

  • 封锁只针对Google服务器,Facebook的hosts仍然可用。
  • 某些Google服务器IP的“大”地址段,成为重灾区。端口不由分说全部封掉。
  • 有些不是很“常规”的Google服务器IP地址段,被GFW进行了“盯防”:一旦发现有用户对其443端口进行访问,随即跟去判断证书上标识的域名。如果是*.google.com,一分钟之内80/443端口就会被封掉。要过很长一段时间才会解封。


还剩两个,都是躲在邮件服务器丛中被我挖出来的,真的是好险!但由此可以证明这个事实:不是所有的IP地址都会被封锁和“盯防”。

如果是这样,那就还好。看来:

  • GFW也没能掌握所有的Google服务器IP地址段。而且就算是Google在文档中明确标出的IP地址段,GFW也没封全。
  • 文档中未明确标出的Google服务器被按证书“盯防”,说明GFW刚采集到这些地址,还拿不太准。
  • 泄漏得比较多的地址被优先“盯防”,说明GFW(至少)有靠人工收集hosts。不排除翻墙人群中有“卧底”(这个简直是废话)。


我靠着这两个漏网之鱼,靠着数据挖掘和关联分析(其实就是人肉搜索啦),自己又搜了十几个hosts出来。都是不在任何相关列表中的IP地址段,分散在十余个不同的国家里。估计GFW不开白名单的话,撑过六月份应该问题不大吧。

2014年5月7日星期三

BCB5在Win7 x64上启动时报错“1 transfer item(s) contain syntax errors”

由于WinXP已经被微软官方宣告服务终止,最近把工作环境升级到了Win7,并且安装的是x64版本。装了之后发现,BCB5启动的时候会弹出一个报错对话框,里面的信息很奇怪:
1 transfer item(s) contain syntax errors
点“确定”关闭对话框之后,BCB5使用起来也没有什么问题。但每次启动都会弹框,很讨厌。那么,这是什么情况呢?

一般来讲,Win7与WinXP之间,出现类似兼容性问题的原因大致有:

  • 管理员权限问题
  • 注册表键值问题
  • 系统目录问题
  • DEP问题

在x64系统上,目录问题尤其突出。Program Files现在还有个Program Files (x86)。System32那边也有个SysWOW64。后者一般跟应用软件关系还不太大,但前者常常会导致很多问题。我就见过有的软件安装包都会运行出现问题。

这次的情况其实也类似。照例,先上国外网站的链接。
http://codeverge.com/embarcadero.cppbuilder.install/at-start-up-1-transfer-item-s/1096695
最后那个回复,把操作步骤写得很详尽。做C/C++开发的,英语阅读一般还是不会有问题,我就不翻译了。

总之呢,这个问题就是因为Program Files (x86)直接引起的。另一个回复里面说把BCB5卸载后重新安装在Program Files下也能解决。当然,有问题的地方其实只有一处,所以完全没必要如此大动干戈。

2014年3月20日星期四

为什么不用动态内存分配?

在写这篇Blog的时候,我考虑了几分钟,在想要不要把标题写成《为什么有的程序员喜欢用动态内存分配?》。最后我还是把那些修饰词和定语给删了。虽然那个标题更准确一点,但是本文基本上是一篇吐槽文,我还是比较喜欢这种反问句的感觉。

事情是这样开始的:
在工作中,遇到了别的同事以前写的一段代码。作用是显示从某些网上下载的文件的内容。文件下载完后,也在本地保存了一份副本,这样如果下次发现本地有副本,就直接显示不用下载了。
这基本上是一个类似浏览器缓存的功能,实现起来也不难。不过这次我碰到一个Bug,有个文件的副本,在解析的时候报错了。
因为第一次下载的时候并没有报错,所以焦点就集中到这个缓存机制上。这里面有个值得关注的地方在于,大概是出于节省本地硬盘空间的考虑,本地的副本在保存时是压缩过的。于是问题可能出在两个地方:

  • 压缩算法有问题,压缩保存的时候,把文件给弄坏了。
  • 解压缩算法有问题,无法正确还原这个文件。

这套压缩/解压缩的算法,是开源的(zlib)。所以我认为问题不应该出在算法本身,更可能是用法没用对。调用代码大概是这个样子的:
#define chunk 16384
void compress_file(const char* source_file , const char* dest_file)
{
    unsigned char datein[chunk];
    unsigned char dateout[chunk];
    unsigned long datelong = chunk;
    unsigned long sourcelong;
    FILE* source;
    FILE* dest;
    source = fopen(source_file , "r");
    dest = fopen(dest_file, "w+b");
    while (!feof(source))
    {
        sourcelong = fread(datein, 1, chunk, source);
        compress(dateout, &datelong, datein, sourcelong, 1);
        fwrite(dateout, datelong, 1, dest);
    }
    fclose(source);
    fclose(dest);
}
void un_compress_file(const char* source_file , const char* dest_file)
{
    unsigned char datein[chunk];
    unsigned char dateout[chunk];
    unsigned long datelong = chunk;
    unsigned long sourcelong;
    FILE* source;
    FILE* dest;
    source = fopen(source_file , "r+b");
    dest = fopen(dest_file , "w");
    while (!feof(source))
    {
        sourcelong = fread(datein, 1, chun, source);
        datelong = chunk;
        if (uncompress(dateout, &datelong, datein, sourcelong))
        {
            fwrite(dateout, datelong, 1, dest );
        }
    }
    fclose(source);
    fclose(dest);
}
这段代码我也不打算在这里分析太多,问题很明显:代码编写的初衷,是想把文件分块处理。但每块数据压缩之后的大小并没有记录在压缩文件中,也没有采取一些诸如分隔符或区块补齐之类的定位措施,所以解压缩的时候实际上是无法忠实地按压缩时的分块来还原数据的。而出问题的那个文件,大小的确是超过了16384,于是就被弄坏了。

这里就引出了一个问题:为什么要分块?
事实上,如果这段代码没有采用固定长度的C-style数组,而是用动态内存分配的解决方案,压根都不会需要分块,也就不会出现这个Bug。当然,这只是解决这个Bug的方案之一。对分块压缩算法的理解有问题,也是造成这个Bug的原因之一。从这方面着手进行改进也是可以的,各有利弊而已。
但这不是我要表达的重点。在这个案例里,下载的文件并不会很大,几十KB就顶天了。我真正疑惑的地方在于:为什么不用动态内存分配?
可能的解释有:
  • 担心内存碎片问题
  • 担心忘记释放
  • 嫌动态分配内存麻烦
  • 习惯了这种固定长度缓冲区的写法
  • ……
也许还有别的原因,一时半会儿我是想不到了。

那么换个问题:什么时候该用动态内存分配?
这个答案会比较明确一点:
  • 空间大小不确定(运行期确定)
  • 栈上空间不够
  • 方便与线程外部传递/分享数据

在本文的这个例子中,文件的长度是不确定的,每块数据压缩后的长度也是不确定的。很明显,这就是属于应该用上动态内存分配的时候。
该用的时候不用,带来的恶果就是程序的可读性和可维护性就会变得差,出Bug的机会更高。毕竟固定长度的内存区域就一定要处理溢出问题。而且用固定长度去处理变长内容,要分块/分次,要做循环,要留意退出条件,测试时要覆盖1和N……,这些都带来了不必要的开销。
还不如直接分配一块内存出来,只要到时候记得回收就OK。性能方面值得担心的话,也可以自己优化内存管理,这是可以集中处理掉的事情。而那种用固定长度的栈缓冲区来解决此类问题的办法,好听一点叫做“质朴”,难听一点叫“土”。总不能每个需要动态内存分配的地方,都用这种土办法来应对吧。

我其实是觉得,有些程序员,会有意识(或下意识)地避免用动态内存分配。从写代码的时候就开始重视性能,是好事情,但写程序不能只看功能和性能。你写的程序,好不好懂,容不容易出问题,有没有定时炸弹,好不好改,方不方便扩展,这些也都是很重要的。性能不佳可以优化,这种代码级的性能问题(相比架构级而言)优化起来尤其容易。但其它的方面,要改善起来绝非一日之功。
往开了说,作为程序员,应该避免陷入“某个东西就是不好”的思维方式中。思维开始变得狭隘,是自身没法继续再提高(达到上限了)的标志之一。

2014年1月22日星期三

2014年1月全国性DNS劫持事件评析

许久没更新博客了。这次全国性事件既然这么轰动,震惊互联网界及翻墙界,那我就借此机会说上两句。

事件是15:20开始的,而我当时15:30刚好有个会,所以这个事件只经历了一点开头:
当时我正在整理自己的收藏夹,进行到windbg和ollydbg的时候,发现需要翻墙才能访问了。刚开始我在疑惑为啥GFW会对调试工具下手,难道愚民政策已经扩展到技术界了?随后我发现大部分时间这两个网站的域名被解析到了 65.49.2.178 这个IP上。少部分时间的尝试是正确的,但这个概率小得不足以完成大部分文件的载入。由于我用的DNS一直都是四个8,所以第一个反应就是这两个站点被DNS污染了。
既然是污染,那么应该能抓到正确的DNS回应包,只是慢点而已。但这次我发现DNS回应包是一对一的,没有多余的包回来。只是第一次解析的时候往往能解析到正确的地址上,后面再解析,回复的就是65.49.2.178了。当时我还没试别的网站。
然后开会的时间到了,我就走了。再回来的时候,故障已经基本结束了,没什么时间和机会去分析。技术方面的分析,可以参考这个。我认为分析得靠谱,符合此次事件的各种特征。我在这里只补充一些文中没有提到的部分。

首先,这不是“DNS污染”,是“DNS劫持”。
我这里不是在抠字眼,或者讨论这两个词的定义问题。我只是指出这个事实:这次GFW对于DNS的攻击方式,跟以往(或者说一直以来)的DNS污染有所不同。
一般,GFW的做法是抢在DNS服务器的正常应答之前,伪造一个应答,欺骗客户端。正常的应答仍旧会返回到客户端,只不过GFW的欺骗包会很快,相当快,使得客户端不理睬正常的回应包。
但这次不同,从抓包的结果看来,“一问一答”,并没有多余的回应包。即使DNS是境外的8.8.8.8,也是如此。境内的DNS,尚有别的办法可以进行控制。境外的DNS,必须是在DNS查询/回应包的转发路径上对其进行劫持/丢弃,才能实现这种效果。

其次,探索一下GFW这次这个DNS劫持功能的工作模式。
通常而言,要进行DNS劫持,GFW可以有两种基本做法:
  • 劫持DNS查询包:截获DNS查询包,不把它向目的DNS进行转发,然后自己伪造一个DNS回应包给客户端发去。
  • 丢弃DNS回应包:截获DNS回应包,伪造一个DNS回应包发给客户端,然后把正确的回应包丢弃,使其不能正常到达客户端。
实际上的情况,可能比这要更复杂一点。比如,丢包的事情,应该是GFW的一个状态防火墙完成的。而防火墙的规则添加可能需要一点时间,所以第一次查询时有可能会有正确的回应包漏过。
另外,根据每次都是“一问一答”看来,伪造的DNS回应包可能是防火墙规则自动触发。也就是说,DNS回应包被拦截后,才会伪造一个发给客户端。如果没被拦截,就不会伪造。否则无法解释第一次查询时正确的回应包漏过之时为什么也是“一问一答”。
综合上述情况,并结合GFW的部署和需求特点,这次的DNS劫持功能应该是采用的第二种工作模式,也就是说对DNS回应包进行处理。很显然,对于GFW而言:从“非受控区域”过来的数据,才是真正需要控制的“有害数据”。从“受控区域”出去的数据,就算会被判定为“有害”,也没必要进行处理,守株待兔就可以,说不定对方根本就不存在呢。

顺便,对GFW的一些技术细节,从这次事件可以有更多的认识。
要完成DNS劫持,有一个前提:GFW可以控制DNS包转发路径中的(至少)某个路由器,或者GFW自身(的一部分)就是DNS包转发路径中串进去的一环。相比之下,如果要做到以前的DNS污染,只需要在交换机上旁路接入一台设备,不需要串在路由路径中。
具体而言,从这个DNS劫持的功能看来,应该会有三个部件参与:
  • 识别模块:这个可以由一个IDS性质的设备来完成。对来自“非受控区域”的DNS回应包进行检测。这个完全可以在旁路慢慢做,不影响网络出口的性能。
  • 过滤模块:当识别模块检测到“有害信息”后,会向一个状态防火墙添加一条动态规则。生效不一定很快,但因为是全国性质的,漏也漏不了多少。这条动态规则包括丢弃符合条件的DNS回应包,以及驱动欺骗模块去伪造一个DNS回应包。这个设备必须串入骨干路由,应该是部署在互联网出口处,基本上必须是一个群集。
  • 欺骗模块:伪造的工作是跟过滤模块联动的,即:丢弃-伪造。这个模块以前应该就存在,部署在旁路上就可以。

回头想想,这些都并不是什么前沿的技术。花不了多少时间我自己都能写出来。目前阻碍这个功能(DNS劫持)大规模应用的因素,可能主要还是来自性能方面的压力。否则现在对那些敏感域名仍然在大量采用的低效的DNS污染早就该换成劫持了。在性能方面而言,用旁路模式当然会好很多。有关人等大概也知道,在DNS上无论怎么折腾,也都是锁君子锁不住小人,索性不把宝贵的性能浪费在这里了。