Random Stuff from GlacJAY

last update:

由于 OpenVPN 本身协议的特殊性,用一般的方法不太好测它的并发。看过 LoadRunner ,但也最多只支持标准的 SSL/TLS 协议(当然,我也没细看这个)。于是动手改了其客户端的实现,最终完成任务。

其实阻止我们在一台机器上同时跑很多 OpenVPN 客户端的因素就只有虚拟网卡一个。貌似装十个左右的虚拟网卡驱动之后,机器就不行了。于是解决办法也很简单,把虚拟网卡相关的功能跳过就可以了。根据上篇的说明,只要在 incoming_push_message() 函数中,把对 do_up() 的调用直接换成 initialization_sequence_completed() 就 OK 了。

题外话:Eclipse CDT 很给力,至少在我用起来,比 gVim + Cscope 或者 SourceInsight 要来得给力,推荐一下。

更准确的来说,是 OpenVPN 的客户端与服务端之间,从协商密钥、到推送配置,以及最后的网卡与路由配置生效,开始进行 IP 报文的传递,这整个的过程。

完了。嗯,整个过程就像上面说的,这几个步骤而已。

不过重点当然还是代码啦。以前一直以为 OpenVPN 的点对点模式下,两端会进行一个决定谁是客户端,谁是服务端的协商过程,一直都想知道是怎么做的。后来才知道,原来通过配置信息,就已经决定好这个了。当然,我下面说的是客户端-服务器模式。

又是好久没来这儿了啊。

最近因为工作需要(其实也没需要那么多),一直在断断续续地看 OpenVPN 的代码,终于大概搞清楚了它的握手是怎么个流程了。简单来说的话其实非常的简单,首先在 reliable 模块中实现了一个可靠的 UDP 报文协议,就是加上超时重传和确认报文的功能;然后用该协议交换一个 Hard Reset 命令,开始握手;最后建立 SSL 对象,并且通过内存 BIO 在可靠 UDP 协议的基础上转发 OpenSSL 的握手协议报文,通过这个 SSL 连接交换 OpenVPN 自己的密钥。接下来就是用这些密钥,该干嘛干嘛了。

在我的 XTunnel 项目中,已经用 Python 作过这种相对底层的工作了(这说明 Python 果然还是非常强大的,上下层通吃啊),不过那边目前还是只实现了 Linux 的版本。后来我又陆陆续续地把 Windows 以及 Mac 下的操作方法给搞通了,今天就来总结一下。

在 Linux 内核中,特别是在现在的发行版中,应该都已经有了 TUN/TAP 虚拟网卡的驱动程序,看一下有没有 /dev/net/tun 这个文件就可以知道了。如果没有,就执行一下 sudo modprobe tun 这个命令吧。如果还是没有,那就 Google 之吧。下面上代码:

首先,你要安装好 UnixODBC 软件包,这个就不多说了。

然后,安装 Oracle 官方客户端,因为我的使用环境为 Fedora 12 ,所以我下载安装的是 oracle-xe-client-10.2.0.1-1.0.i386.rpm

装好之后,要设置一些环境变量,我是用的一个 Shell 脚本来完成这项工作的,你可以把它放在 /etc/profile.d/ 目录下并加上可执行权限来让其在系统启动时自动执行,也可以直接运行这个脚本来使其立即生效。脚本如下:

-- 首先是删除该数据库中该用户名下的所有表、序列与触发器, -- 其中触发器是通过表格级联删除的。 declare cursor usertables is select * from user_tables where table_name not like 'BIN$%'; cursor usersequences is select * from user_sequences; begin for next_row in usertables loop execute immediate 'drop table ' || next_row.table_name || ' cascade constraints'; end loop; for next_row in usersequences loop execute immediate 'drop sequence ' || next_row.sequence_name; end loop; end; / -- 然后,就是一砣……的建表语句啦, -- 比方说下面就是两个含外键的表。 create table "A" ( "ID" integer primary

这主意是我一同学想到的(至少是他告诉我的),基于一种实际的需要。假设你有两台内网机,都没有公网地址,你想从一台机器访问另一台机器的服务,这时要怎么办呢?当然很可能是我无知了,就我所知,网上倒是有一些提供这类服务的网站,但都是基于 Windows 的远程桌面的,至于 Linux ,我没找过。

于是那家伙联想到了 IM Bot 这种东西。现在网上有各种各样的 IM Bot ,可以通过与之聊天执行各种各样的自动化任务,那为什么不能让它把发过去的命令交给另一台机器的 Shell 执行,并把结果返回呢?这不就实现了一个简单的 Telnet 了吗?这就是最初的想法了(我没去找现成实现,因为我也该练练手了)。而我刚好才折腾过 OpenVPN ,于是就有了标题所说的这个最终想法。这样的话,就能一下子从只支持一种应用协议到支持几乎所有的应用协议了,而且实现的工作量也同时减到了最低。真是好主意啊,自我夸奖一下 :-)

肯定有许多人遇到过这个问题,也肯定有许多现成的解决方案被发现,可是我没找到(或者说没耐心找)。无所谓,自己找到的话,得到的就不仅仅是最终结果了。

闲话少说。其实以前也干过类似的事情,就是在保存的时候自动去掉所有的行末空白;不过这个操作使用 Vim 本身的功能就能实现,不需要借助于外部程序,所以只要简单地设一个 BufWrite 时的自动命令就行了。但当需要借助外部程序的时候,在 BufWrite 或者 BufWritePre 或者 FileWritePre 时执行的自动命令就不行了,老是提示说什么文件本身已更改,是否确定写入。我在这上面反覆试了好多次,才发现是自己没有搞清楚底下到底发生了什么。要让外部程序对文件内容进行格式化(或者其他什么操作。我想调的是 gofmt,顺带一提),首先当然得要那个外部程序能看到你做过的,还没有保存的更改,所以说应该是先写入再操作的,即在 BufWritePost 的时候执行自动命令。而我一开始就把基本步骤给搞反了。

我的编译环境是 Visual Studio Team System 2008 版本 9.0.21022.8 RTM , Windows Mobile 5.0 SDK R2 ( VS2008 自带的版本)。当然, Perl 也是需要的,我装的是 ActivePerl 。我要编译的 OpenSSL 版本是 0.9.8e 。

VS2008 的安装

那个 Web Developer Tools (好像叫这个)的安装会失败,又不能不装,根据网上的说明,要把它的目录单独从光盘上解压出来安装,且安装的时候要挂 Office 的安装光盘(我的 Office 版本是 2007 )。这个装好了之后,再从光盘上安装 VS2008 就没有问题了。

其实嗫,这个问题已经有标准和其他的解决方案了。标准解决方案参见 Control.Applicative 中的 ZipList ,不过这东东用起来蛮麻烦的说;其他解决方案见 bff 库的 Data.Zippable 模块,嗯,我还没搞明白这玩意怎么用,不过总感觉杀鸡用牛刀了有点(Template Haskell ,以及其他依赖)。

所以,如果你只是跟我一样,看 Data.List 中的那一砣 zipn 不顺眼的话(其实也只是看着不顺哈,用着还是蛮顺的,反正实现不用我写),一个更简单的方案在此: