Browsed by
Category: 学习

学海无涯

量子通信卫星

量子通信卫星

据说今天晚上要发射一颗量子通信卫星,顾名思义就是进行量子通信。对此我感到非常震惊!作为一名科普爱好者,我有限的量子理论知识大概只有以下几点:

(1)量子纠缠态。一个量子分裂成两个量子,这两个量子就是自纠缠的。一个向左转,另一个就向右转。理论上讲,这种纠缠态是跨越空间限制的,即使两个量子分布在宇宙的两端,它们的纠缠状态也不会改变。我猜想量子通信大概就是基于量子纠缠态来通信,通过控制一个量子的状态,影响另一个量子,从而实现通信。从这个角度讲,量子通信简直就是超越光速的通信方式。

(2)测不准原理。这基本就是现代量子理论的基石之一,大概是指无法准确测量量子的状态,因为测量本身就是一种能量干扰,会影响到量子的状态。如果测量某个参数越准确,则其他参数的结果就越不准确。

既然测不准,因此实际上是无法准确控制量子的状态。既然无法准确控制,就不可能实现通信。反过来说,如果实现了通信,则必然有某种手段能准确控制量子的状态,也就是说“测不准原理”是不是可以over了?

理论基石居然有可能被动摇,这简直就是突破天际!怎么做到的?感觉有幸要见证历史,求科普。

2016-08-19 更新:看了一些新闻报道,貌似是利用光子的不可分割、不可复制特点,产生密钥,对通信进行加密。当然这仍然很厉害,但是完全不是『利用量子纠缠态进行远距离通信』。我觉得『量子通信』这个表达不准确,应该是『量子加密』才对,天际并没有被突破。

渐行渐远的南山书城

渐行渐远的南山书城

儿子非常喜欢南山书城,逢年过节或者放假的时候,都会去一趟书城并买点书回家。在书城里,儿子特别喜欢和小朋友一起坐在地上看书,并相互讨论。因为这样,我也渐渐喜欢上书城看书,在儿子看书的时候,我也能逛逛,挑选自己喜欢的书。

虽然在网上能买到更便宜的书,但是我们仍然保留了逛书城的习惯,并乐意从中购买自己喜欢的书。

而今年六一的经历实在不愉快,严重影响了心情。貌似南山书城今年重新装修了4楼的少儿部分。书柜更多了,书也更多了,相应给孩子们阅读的空间反而少了。更糟糕的是,时不时有些工作人员过来把孩子们赶起来,不让坐在地上看书。貌似要赶到3楼一个小区域去看书。

不知道这是谁出的鬼主意,实在太糟糕了。3楼那个小区域根本容不下多少孩子坐下来看书,而且那个区域还有商业活动!实际上,南山书城现在看书的位置越来越少,而卖东西的商铺越来越多。

如果不能席地而坐读书,就只能站着看了。我强烈不满,于是向工作人员反应,要求像以前一样可以坐地板上看书,要不然干吗来书城?直接在网上买不就得了?谁知道工作人员轻描淡写地说:那就去网上买好了。

我不知道南山书城是怎样一个机构,也不清楚其商业运营是否成功,但是商铺越来越多,阅读空间越来越少,这不是一个书城该有的态度。装修再豪华也没有意义,已经背离了书城的本质。

是的,我们当然可以选择上网买书。

微信读书

微信读书

这是腾讯新推出的一个手机端读书软件(在iPad上也可以用),非常好用。

我比较喜欢的是读书时长可以换书币,然后又可以用书币去购买书。虽然每周的兑换额度有限制,不过对一般的书迷来说,其实都足够了。比如我,到目前为止,已经“免费”购买并看完了:吕思勉《中国通史》、霍金《时间简史》、刘慈欣《三体(全集)》。还乘机囤了几本好书,例如王小波系列等。

“微信读书”还有几个比较有意思的特点,例如写书评,例如好友排名。说到好友排名,我大部分时间都是好友中的读书冠军,有若干次被其他好友超越,倒真是被刺激了一下,暗暗较劲。

当然,最重要的特点还是真能从中淘到不少好书,是广大书迷的福音。

解决DNS污染

解决DNS污染

DNS污染可能是一个比较普遍的问题,主要表现在:(1)DNS查询返回的IP地址根本是错误的。“错误”意思是IP地址要么根本不存在,要么就是个和域名完全无关系的地址。(2)IP地址虽然可能是对的,但是其他参数被莫名修改,例如TTL参数等。

测试了各类DNS服务器,例如阿里DNS、DNSPod(鹅厂)、Google DNS等。无一例外,最终的结果都或多或少被一些看不见的手给修改、甚至屏蔽了。从技术角度上讲,DNS协议本身非常随意、非常粗糙,是典型的互联网蛮荒时代的产物,比如面向UDP、无加密、无鉴权等,因此网络上任何一只手都有可能修改DNS的查询结果。网络进化到IPv6阶段,当然能解决这个问题,不过既然目前绝大部分设备还只支持IPv4协议栈,因此我们还是不得不修修补补来解决这个污染问题。

最根本的解决方法就是加密DNS查询。目前有些DNS服务商提供了私有的加密DNS方式,不过不太通用,需要私有的客户端程序配合。实际上可以不用搞这么复杂,自己建立加密通道,传递DNS消息即可。例如,参考下图的拓扑逻辑:

实现简单DNS透传的逻辑单元
实现简单DNS透传的逻辑单元

在这个网络中,有两个关键程序:dnsProxy和dnsAgent。

dnsProxy顾名思义就是个Proxy,本身并不负责DNS协议的解析,也不保存DNS的查询结果等信息,只是单纯地将DNS消息传递给真正的DNS服务器,并返回相应的结果即可。dnsProxy另一个功能是对外提供加密的数据连接,例如TLS、SSL加密等,甚至可以只是简单地对数据包进行自定义的异或运算即可。另外就是对外提供非标准连接接口,这点非常重要。DNS采用标准UDP53接口作为DNS服务器接口,网络上那些看不见的手,往往就是扫描并篡改53接口的数据包。这个小程序跑在境外(大家都懂的)的一台VPS设备上,推荐采用DigitalOcean,专业的云计算服务商,采用SSD硬盘,价格公道,我们一直用TA,如果你有兴趣的话,请点击这里自行了解细节。

dnsAgent是另一个小程序,主要负责建立与dnsProxy的加密连接,接收普通设备的DNS请求并将其传递给dnsProxy,同时返回DNS结果给普通计算设备。对于网内设备而言,dnsAgent就是个伪装的DNS服务器。同样,dnsAgent其实也不需要关心、也不需要解析DNS协议细节。在我的网络中,dnsAgent跑在一台常年吃灰的树莓派上(还是第一代的)。

实现这些仅仅需要一点UDP、TCP的网络知识,甚至不需要了解DNS协议的细节,无需对DNS数据包做修改。完成后可以愉快地打开很多以前打不开的网站。当然,有些网站始终是打不开的,这是另一个与DNS无关的话题了。

Pi打开IPv6

Pi打开IPv6

默认已经安装了IPv6协议栈,但是没有打开IPv6功能,这点比较奇怪。不过打开IPv6功能也不复杂,一行命令即可:

sudo modprobe ipv6
6to4 tunnel

6to4 tunnel

今天无意中发现,居然不用翻墙就能打开google和gmail,这简直太不科学了,我朝气象从此焕然一新?

本着“怀着最大的恶意揣测他人”的精神,我对此充满疑虑。于是拉出wireshark仔细dig了一下,发现了IPv6数据包,竟然是通过IPv6访问google和gmail!墙没有封锁IPv6,这实在是个惊奇的发现。

难道电信已经开始部署IPv6网络了吗?对此同样充满疑虑。但是有一点是肯定的:最近买的路由器是支持IPv6的。进入路由器管理界面,发现电信仍然是分配IPv4地址,但是在路由器IPv6设置项中,配置了“自动检测IPv6类型”,检测结果是“6to4 tunnel”,而且配置了IPv6地址。

看起来电信的确升级了网络,但是仍然没有真正部署IPv6,还在半遮半掩中,并且猥琐地限速了。有“6to4 tunnel”也还好,至少能访问外部IPv6的服务器地址。google和gmail等都部署了IPv6,因此可以通过IPv6来访问这些服务。而对于没有部署IPv6的服务,例如twitter之流等,依然还是无法访问。

不管怎样,这已经是向前迈进了一步。真心希望步子能迈得更大些!

2016-03-10 更新:好吧,我承认我还是图样了。

为什么放弃了webRTC?

为什么放弃了webRTC?

首先必须要说明的是:webRTC是非常好的技术,以至于我现在仍然在怀疑,放弃webRTC是不是个明智的决定,内心依然是忐忑不安。

然而现状就是将webRTC从MSS新版本中砍掉了。下面试图说明清楚做决定时的一些考虑。

从webRTC技术的发展脉络看,感觉ta更适合于公共网络的通信,尤其是越来越像专为google hangouts服务。由于是服务于公共网络,因此“加密”提高到一个非常重要的位置,几乎达到了神经质的地步。webRTC设计之初就没有考虑过传统的VoIP网络(尽管该技术来自于收购的GIPS团队,而该团队本身就是为VoIP网络开发出身的),从传输到业务,基本都特立独行。当然,这没什么不好,只是由于与传统VoIP网络切割开来,实在让人经常感到惋惜。

既然没有考虑传统VoIP网络,当然就更不可能考虑网络部署的多样性。全方位加密固然让自己显得安全,带来心理上的安慰,但也增加了网络部署的复杂性(VoIP本身已经够复杂了)。就一般的VoIP应用而言,“salt+MD5”以及SRTP已经足够保证通信的安全性和私密性。而最新的webRTC(不特别说明的话,这里我们总是指Chrome的webRTC实现)要求getUserMedia等操作必须是来自加密(HTTPS)的网站,websocket也必须进行加密。这也就是说,用户必须要为webRTC服务器(通常也是呼叫服务器或者IPPBX)部署单独的签名加密(TLS或者SSL)。对于提供公众服务的网站而言,部署TLS/SSL不是太大问题,而要求中小企业申请签名并部署在呼叫服务器中,这毫无疑问极大地增加了系统的复杂度,增加了部署难度,而且这样做的意义又有多大了?在企业通信网络里与其这样增加复杂度(网络复杂度和管理复杂度),还不如干脆直接建立VPN网络,方案很成熟,加密更全面,保护更周到,方式方法也简单得多。

这就是我们感觉webRTC只适合公众网络并且已经神经质的原因之一。何况,“加密”有时候更多的是个管理问题而不是技术问题。

webRTC另一个宏大的目标是提供各平台统一的用户体验。愿望是很美好的,但是是否能实现值得商榷。把所有的处理都放入浏览器,固然增加了可移植性,但最大的问题也就是牺牲了平台的独特性和高效性。比如在移动平台,webRTC的耗电量就明显偏高。而且在移动平台各种莫名其妙的设定,极大地损害了用户体验,比如播放ring-back tone,居然要求用户必须点击一个按钮才能继续(是我out了么?),这实在是太扯了。

而最被我们诟病的是兼容性。webRTC基本没有什么兼容性可言。按道理已经发布这么久了,多少应该在一些关键点上考虑一下兼容性,然而并没有。这对一个像google hangouts这样的网站来说,不是大问题,用户无非升级一下chrome好了。而对部署在许许多多用户voip网络中的PBX或者webRTC服务器而言,就是噩梦了。用户升级了Chrome,就必须同时升级服务器,如果不升级服务器,就必须降级Chrome。与之相比,microsoft对兼容性的考虑简直贴心贴肺。

这种对兼容性的唾弃有时候甚至直接表现在产品本身。比如当初的Gtalk,直接就放弃了,我们花费大量时间精力对接Gtalk,最后也是然并卵。对webRTC也会产生同样的顾虑。

webRTC当然有很多非常优秀的技术特点,比如源自GIPS的回音消除技术、超强的语音编解码技术等。思虑再三,决定还是不再跟随,砍了算了,以后再说吧。

实现一个简单的SMTP发送库

实现一个简单的SMTP发送库

最近在优化“语音邮箱”业务时,发现采用python-smtplib库虽然能满足需要,但是还是有很多不足,因此决定自己重新写一个库,当然仅仅实现发送email(包含附件)即可。实现一个完整的SMTP服务可能比较复杂,而实现一个单纯的、高性能的SMTP客户端发送库却比较容易。

与SIP、HTTP等协议类似,SMTP也采用文本方式定义消息格式,而附件等二进制内容,则采用base64转码成文本,这样就极为方便开发和调试。以下是SMTP最基础的几个RFC文档:

RFC5321: SMTP
RFC5322: Internet message format
RFC4954: SMTP Service Extension for Authentication
RFC3207: SMTP Service Extension for Secure SMTP over Transport Layer Security
RFC2035: Multipurpose Internet Mail Extensions

我们结合SMTP的流程,来简要说明SMTP协议中的各个关键点。

一、标准端口

SMTP基于TCP连接,SMTP服务器默认打开的端口是25、587或者465。通常是采用25端口,后期设计加密SMTP(即SMTPS)时采用了465端口。而IANA在新业务端口规划时占用了465端口,因此将587端口定义为TLS加密的SMTP端口。

目前各email服务商通常都会同时打开25和587端口,有些为了和以前老客户端程序兼容,也会打开465端口。

这里面其实可能存在一个误解,似乎25端口就是不加密的SMTP,而587、465就是加密的SMTP。实际上不是这样,现代SMTP服务器一般都已经支持STARTTLS(即RFC3207),因此在25端口也可以启动SSL/TLS加密,这取决于客户端是否具备SSL/TLS加密、解密能力,这点在后续流程中会详细描述。

二、基础流程

2.1 建立与SMTP服务器的连接

建立TCP连接,连接到服务器的25端口或者587端口。如果是25端口,则是建立普通TCP连接即可。如果是587端口,通常可以直接建立SSL/TLS连接。需要注意的是,有些SMTP服务器的587端口也是要求普通TCP连接,后续STARTTLS流程中再启动SSL/TLS加密。这种情况下,587端口的流程与25端口的流程一致。

我们的示例流程中,采用QQMail的SMTP服务器做参考,因此我们首先向“smtp.qq.com”服务器的25端口建立连接。连接成功后,服务器应返回220消息,告诉客户端连接成功:

220 smtp.qq.com Esmtp QQ Mail Server

2.2 初次握手

SMTP客户端发送EHLO命令给服务器,进行初次握手协商:

EHLO 192.168.1.101

“EHLO”实际是ESMTP(Extended SMTP)的指令,意思是要进行用户名和密码的鉴权。远古时代的SMTP不需要鉴权的情况下,可以直接发送HELO命令进行握手。目前的SMTP服务器基本都是支持ESMTP,因此如果不刻意区分的话,后续的SMTP实际就是指ESMTP。

SMTP服务器器收到上述消息后,返回本服务器的一些能力信息给客户端:

250-smtp.qq.com
250-PIPELINING
250-SIZE 73400320
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME

其中最关键的就是STARTTLS能力,也就是该SMTP服务器具备加密连接能力。通常都建议采用加密连接以确保数据安全,毕竟互联网上总有一些黑暗势力在窥探您的信息。

如果客户端不具备SSL/TLS能力,则直接跳到“账户鉴权”流程即可。此时就不能采用PLAIN鉴权模式,必须采用MD5等加密鉴权模式。

2.3 加密连接

既然服务器明确了SSL/TLS能力,因此客户端只要启动SSL/TLS加密TCP连接即可。客户端发送STARTTLS命令,通知服务器准备加密:

STARTTLS

服务器返回响应消息,通知客户端可以开始加密:

220 Ready to start TLS

接下来就是在TCP连接上建立SSL/TLS加密连接,后续通信以后都基于SSL/TLS连接。

请注意,QQMail服务器目前似乎只支持SSLv2、SSLv3加密,不支持TLSv1.0,TLSv1.1和TLSv1.2加密,其他的SMTP服务器(例如outlook、gmail等)则支持全部加密方式。

2.4 第二次握手

加密连接建立后,再次发送EHLO命令进行握手:

EHLO 192.168.1.101

同样,服务器返回相应能力进行响应。此时,通常不再包含STARTTLS指令了:

250-smtp.qq.com
250-PIPELINING
250-SIZE 73400320
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME

2.5 账户鉴权

鉴权有多种方式,其中PLAIN方式是要求所有SMTP服务器都必须具备的。在未加密的情况下,采用PLAIN方式无疑会泄露账户密码信息。而在已经加密的SSL/TLS连接里,则不存在这个问题,因此我们采用了最简单的PLAIN方式传递账户密码信息进行鉴权。

PLAIN方式很简单,采用”\0user name\0password”进行编码,然后base64转化成文本格式即可。

客户端发送以下鉴权命令:

AUTH PLAIN my_demo_base64_string_here

服务器鉴权成功,返回响应消息:

235 Authentication successful

2.6 提交邮件地址信息

鉴权成功后,客户端可以开始告诉服务器邮件地址信息,例如发送者、接收者等。此类消息不一一累述,请直接参考以下消息流:

MAIL From:<Iloveu@foxmail.com>
250 Ok
RCPT To:<Iloveu2@msn.com>
250 Ok

2.7 准备递交邮件内容

客户端发送DATA命令,告诉服务器准备提交内容:

DATA

服务器返回响应消息,通知客户端可以开始发送数据:

354 End data with <CR><LF>.<CR><LF>

由于后续数据都采用文本编码,因此标准规定用“\r\n.\r\n”标识数据发送结束,也就是SMTP服务器在上述响应消息中指示的“<CR><LF>.<CR><LF>”。

2.8 发送邮件内容

邮件采用文本格式,附件采用base64编码,可以分多次发送,以下为一个简单示例:

From: <Ilovu@foxmail.com>
To: <Iloveu2@msn.com>
Subject: You have a new voice mail: From 301 Day 2015-12-14 Time 10.29.7
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="==491D4D07305F440E009A0125=="

--==491D4D07305F440E009A0125==
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="From 301 Day 2015-12-14 Time 10.29.7.wav"

UklGRpKaAABXQVZFZm10IBIAAAAGAAEAQB8AAEAfA......
--==491D4D07305F440E009A0125==--
.

对于有附件的情况,应在Content-Type中指明boundary参数,例如本例中的“==491D4D07305F440E009A0125==”。而附件内容起始处用“–boundary参数”标识,附件结尾用“–boundary参数–”标识。

发送完数据后,服务器响应消息:

250 Ok: queued as

2.9 结束

发送完邮件后,客户端友好地向服务器告别:

QUIT

服务器也友好地告别:

221 Bye

最后关闭TCP连接,完成整个流程。

掉坑里了

掉坑里了

Qt无疑是个非常好的framework,我们一直用TA。虽然不敢说已经是行家里手,不过好歹也开发这么久程序了,渐渐地有些自负起来,因此掉坑里了。

坑来自Qt最经典的设计:signal-slot。我以前的理解这是异步的,常用于模块间解耦。在windows平台,这个理解似乎没错,signal-slot底层依赖window的message机制。而在linux平台,其实现方式默认仍然是callback机制。

callback机制在多线程编程里最容易出问题的就是“锁”。这次掉坑里,就是在slot中应用“锁”时不小心,导致了死锁。

这次竟然忘了这点! :-(

virtualbox无法启动虚拟机

virtualbox无法启动虚拟机

前几天系统升级到win10,初步体验了一下,感觉不如win7,不过已经升了,也就算了。但是比较闹心的是,virtualbox无法启动虚拟机了!vbox中共创建了两个虚拟机,分别是Debian7(32bit)和Debian7(64bit),都无法启动,一启动就报错:VERR_VM_DRIVER_VERSION_MISMATCH。

在网上查了很久,并重新装了vbox的4.x版本和最新的5.x版本,问题始终存在,一度误解为win10的问题。今天无意中发现vbox安装目录下有driver目录,考虑到出错提示的信息隐约和驱动有关,因此试试安装了其中的驱动,问题居然就好了! 安装文件为以下文件(视vbox具体安装目录而异),右键点击文件,然后点击“安装”即可:

D:\Program Files\Oracle\VirtualBox\drivers\vboxdrv\VBoxDrv.inf

回顾问题,究其原因可能在于win10是升级,而不是全新安装,因此残留了vbox以前的一些配置,而这些信息在两个系统中又是不一致的。vbox自身也有问题,删除旧版本时显然没删干净,至少旧的驱动程序保留下来了。