浅析“TCP Proxy”设计

Sina WeiboBaiduLinkedInQQGoogle+RedditEvernote分享




在入行网络安全领域之前,笔者并不知道这个东东的存在。对于主机软件研发人员和以及传统的路由交换研发人员,TCP Proxy这个模块并不存在。但是对于网络安全设备厂商而言,该模块至为重要。笔者所在的公司也有自己研发的TCP Proxy模块,但是本人从未阅读过模块的代码和设计(不读的原因是没有那个闲工夫)。本文是根据笔者对于上层安全应用特点以及TCP协议栈的经验总结的一些个人对于这个模块的设计看法,未必完全正确。

1.应用需求

image

 

上图是本人早年绘制的,是笔者对于TCP Proxy需求的理解。

九阴神功第一层For IDS:这个时候TCP Proxy需要尽力而为重组流量,但因为有些IDS工作在sniffer模式,而非inline,因此CPU处理速度可能无法match traffic的速度,遗漏一些报文,无法收齐报文是正常的。例如TCP Proxy可能会看到Ack来了,却没有收到对应的数据信息,这是正常的,表示遗漏了报文。

九阴神功第二层For IPS:同IDS不同,IPS必然是inline部署,此时肯定是可以收全报文的,否则则表示设备的网络部署有问题,因此TCP Proxy的实现可以相对严格。

九阴神功第三层For ALG:因为ALG需要根据NAT信息修改报文内容,因此对于ALG来说,TCP Proxy是Writable。而不像前两者那样是只读的,这就要求Proxy要handle序号更改、报文生成之类的东东。

九阴神功第四层For Host:不用多说了,一个full TCP协议栈(注意:这里仅仅用于对比,而不是一个TCP Proxy了)。与前述的东东相比,主机TCP协议最显著的特性就是要支持TCP之中的几个Timer,而且作为Internet的参与者,各种拥塞控制的义务是一定要尽到的,否则Internet很容易塞车。

九阴神功第五层For AV(UTM):这个层面的TCP Proxy原则上有义务实现Full TCP协议栈,至少几个timer是要实现的,可能杂七杂八的选项无法支持全。其相比四层神功的特点是需要协调两端的TCP连接。例如:TCP一段是GE上来的,另一端从WAN出去。此时如果不协调流控,则从GE上来的流量会噎死中间设备。这个增加了系统实现的复杂度。

2.效率考量

看过Socket实现的读者会知道,在协议内容传递到应用的时候,零散的Segment会被拷贝到一个平面缓冲区以供应用读取。对于技术偏着狂来说,这简直就是一种侮辱。因此,笔者考虑,应该可以直接利用原始Segment直接组装成Buffer Chain进行上交,如此可以满足研发人员的0拷贝的快感。

这样提高效率的代价是,应用层要意识到segment的存在,要enhance一些API。例如以往针对平面缓冲区的memcpy等标准库函数要增强其chain的实现。要想做模式匹配也要顾及到这种二维的情况。

3.自适应的设计

实现了上述的所有功能,是否很酷呢,非也:-)

对于使用类Socket的实现异或Buffer Chain的实现,设计上并非是非此即彼。笔者认为可以采用自适应的方式。对于大部分不需要特殊处理的流量采用buffer chain方式,如果需要组起来方便,可以动态提升对应的proxy session的能力。这个想法不知道是否正确,没有细想。

4.TCP Proxy模块的Driver

image

 

具我分析,TCP Proxy有上述的驱动源。

1.XXBuf:适配不同的Pkt结构,这样实现可以应用于不同的系统。

2.XXTimer,适配不同的Timer机制,提供基准时钟,用于驱动TCP协议内的不同定时器。

3.Session,适配不同的Session,如有下层提供session,这里可以用作宿主,保存一些东东。

必不得已而去,于斯三者何先?叶子曰:去Timer,对于ALG、IPS等应用,不需要提供tmer。必不得已而去,于斯二者何先?叶子曰:去Session,大不了大爷我自己组织TCP层的流量表。自古皆有死,TCP Proxy无Pkt不立:-)

5.开源软件的尴尬

目前还没有开源的TCP Proxy实现,一则难度大,二则门外的开发爱好者不了解需求。但是可以负责任的说,哪位大侠有余力搞一个高水平的TCP Proxy开源项目,必然成名立万。当然,一些工程师会为此丢了职位:-)。不过,此模块没有一年半载也搞不出来。当今社会晓畅兵机者多,刚明苦毅者少,至少笔者是没有这个额外精力了。

(2个打分, 平均:1.50 / 5)

雁过留声

“浅析“TCP Proxy”设计”有29个回复

  1. ASR1k 于 2010-03-13 9:44 下午

    这个以前也做过, 最大的难点其实是在转发层面的code上. 当然有C code的接口实现就相对容易些. 但转发平面也会更复杂一些.

  2. appleleaf 于 2010-03-13 11:00 下午

    难点有很多
    1.如何高效实现
    2.如何适应各种上层应用需求
    等等。

  3. gradetwo 于 2010-03-14 12:45 上午

    兄台说的TCP Proxy不只与我的定义的是否相同。
    grinder就是一个Man-in-Middle的TCP Proxy

    http://grinder.sourceforge.net/

  4. appleleaf 于 2010-03-14 1:26 上午

    gradetwo,我看了一下是java项目就没有再看,如果java实现tcp proxy,则必然是基于两边建立两个socket的形式,没有什么太大的用途。

  5. xiaosuo 于 2010-03-14 7:12 下午

    appleleaf说的可是tcp splicing技术?这个lvs项目中有个补丁,也被haproxy所使用了,不过他不支持option。

    基于socket的tcp proxy,用户空间的倒是很多,不过能实现高效确实不容易,为了减少系统调用的开销,lvs的一个tcp proxy子项目将转发放到了内核空间,不过帮助应该不大就是了。Linux提供的操纵内核缓冲区的API splice,在特定的网卡下(支持TSO,并且驱动receive部分是用page map DMA),是可以实现ZERO copy的。目前还不知道哪个项目是用这个的。

    实际上基于socket也没什么不好,能避免很多重复劳动,少走很多弯路,并且在需要转换TCP特性的场合,如TCP WAN acceleration方面还是非常有用的。

  6. est 于 2010-03-14 8:05 下午

    不知道haproxy 算不算呢?

  7. appleleaf 于 2010-03-14 8:07 下午

    多谢楼上两位的回复,我回来研究一下看看。

  8. appleleaf 于 2010-03-14 11:24 下午

    另外est的blog的图片很好玩,视角独特,呵呵。

  9. z 于 2010-03-15 12:41 上午

    “对于技术偏着狂来说,这简直就是一种侮辱。”呵呵,形容的非常生动。

    目前国内有一家fw公司也自己实现了tcpprxy,非常的强大。当然,我相信你们的智商能猜出来是谁的。

  10. droplet 于 2010-03-15 1:55 上午

    TCP proxy的难点在于支持chained application, 传统的socket接口,只能有一个process/thread监听,而不能多个application监听,也就是说,tcp context没办法在多个application之间共享。如果只有一个application,tcp stack的socket interface改一改就可以了(参考以前的khttp,一个in-kernel的web server),如果是chained app,相互之间如何协调就是个问题。如果能够定义一套标准api(基于bsd socket),相信会有很大的价值。

  11. appleleaf 于 2010-03-15 2:06 上午

    那家公司,笔者冒充毕业生混进去看看。

  12. appleleaf 于 2010-03-15 2:09 上午

    to droplet,不算难,就是一个生产者,多个监听者的模型。

  13. llc 于 2010-03-15 2:21 上午

    估计是hillstone…

  14. CNJ 于 2010-03-15 5:48 上午

    “目前国内有一家fw公司也自己实现了tcpprxy,非常的强大。当然,我相信你们的智商能猜出来是谁的”

    是不是每一个做fw的公司都会有自己实现的tcpproxy? 说“非常强大”,仁者见仁智者见智,很难说谁好谁不好吧?

  15. regardlan 于 2012-05-10 2:22 上午

    写了这么多,好像什么也没说呀。

  16. 抓狂 于 2012-05-23 3:14 上午

    最难的是协议栈指纹识别和报文插入、重叠处理。

    报文内容有重叠或重复的时候,不同协议栈处理方式不同(有的丢弃新报文、有的丢弃老报文)。

    除非中间人(proxy)知道每条流两端协议栈类型,否则重组的数据就可能不对,而报文插入、重复是逃避IDS/IPS/FW的最佳手段。

  17. h_f22 于 2012-05-24 9:46 下午

    tcp_proxy这个东西其实没有大家想的那么复杂,当然也不简单,我见过三个fw里面成型的tcp_proxy其实都差不多。不过都各有各的问题,这个东西横亘在中间,没有问题那简直不可能。
    说几点心得:
    1、timer、选项其实不是必要的,拥塞控制其实也没有那么重要,当然proxy的拥塞控制行为跟两端的socket差异很大,需要完全重新考虑,但是绝对没有那么复杂,简单讲两个字,平衡。
    2、最复杂的其实是序列号的对应处理和重传处理混在一起产生的问题。
    3、即使支持改流操作,也没有必要实现完全协议栈。
    4、内存实际上是这个东西的瓶颈,我见过某公司为了这个东西用了40G内存。为什么?大家自己想想吧。
    5、多个buf和平面buf,其实也没那么重要,关键是提供好对应的API,这个东西的效率轮不到这个。为什么?看上一条,加两个字提示——窗口。

  18. 二大妈 于 2012-05-27 12:02 上午

    linux支持tproxy,配合netfilter可以支持上述所有功能。

  19. opensourcer 于 2012-08-09 12:37 上午

    linux下面有靠谱的tcp proxy吗?每次搜索都搜到这个页面,还排在最前面,起码得来个终极解决方案吧?
    他@二大妈,tproxy+netfilter好使吗?

  20. 新手0 于 2012-08-09 10:48 下午

    tproxy还是要把报文送到user space中转,
    本质上还是在为两个socket做tunnel。

    PS:tproxy依赖于外部的iptables策略(解决接管非本地报文的问题),解决方案上不是非常的nice

  21. 新手0 于 2012-08-09 10:54 下午

    刚才的reply怎么不见了?

  22. opensourcer 于 2012-08-09 11:45 下午

    @新手0,谢谢你及时回复。如果我要做这样一件事情,根据经验你看能成吗?tproxy+sshd*做ssh proxy。sshd *是改动过的ssh server,其中加入了ssh client部分。

  23. hritian 于 2012-08-10 6:43 上午

    为什么要用sshd?
    你随便找一个 代理服务器都行呀, nginx或者ha
    proxy ,好像tproxy配套的就是haproxy吧。
    tproxy用肯定没问题, 但是感觉最大的问题是性能吧, 连接数太多的时候性能应该会直线下降。

  24. opensourcer 于 2012-08-12 8:17 下午

    @hritian,现在要做的是一个ssh proxy。nginx或者ha proxy能支持ssh协议吗?这里不希望用户感知到这个proxy的存在,所以需要将用户的命令在sshd解密,然后送入代理客户端跟server建立的连接中去。
    还有比tproxy更好的选择吗?多谢了

  25. Chance 于 2012-11-22 1:21 上午

    wanproxy怎样?我现在需要高性能的tcp proxy,并且数据传输是wan环境,需要对数据进行压缩处理

  26. hritian 于 2012-11-25 5:39 上午

    @opensourcer 没有问题的, 既然是透明代理 ssh客户端和ssh服务器端都感受不到这个代理存在的, 客户端以为是和服务器端连接, 服务器端以为是和客户端的ip连接, tcp proxy是四层的,不需要到应用层。
    如果你的应用连接数不会太多的话,用tproxy就可以了,省事。

  27. pkter 于 2012-12-02 7:29 上午

    @hritian: 我感觉opensourcer的要求是, 这个PROXY必须能decode客户端data。 你说是吗?

  28. Austen 于 2012-12-11 6:14 下午

    设计到网络 协议的,都很复杂,考虑到的问题太多

  29. 低调再低调 于 2012-12-11 9:52 下午

    tproxy在具体应用上还是存在和conntrack及counter配合应用的问题,两个socket是对应一条conntrack还是两条,使用NAT前的IP还是后面的IP,虽然这些都是具体实现问题,但是如果不接地气,很难评估一个方案是否真正可行