网络流量处理中的协议解析二:流重组 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chunhuitrue
V2EX    信息安全

网络流量处理中的协议解析二:流重组

  •  
  •   chunhuitrue 136 天前 1292 次点击
    这是一个创建于 136 天前的主题,其中的信息可能已经有所发展或是发生改变。

    对数据的假设

    在数据包基础上开始协议解析不是不可以,甚至有时候还更简单。比如我们想解析 SMTP 的 maifrom 命令,它几乎在所有邮件通信过程中都完整地在一个单独的包中。甚至字符数量更多的邮件头也是如此。但是却不能作出它们一定就完整地在一个包中的假设,因为 TCP 协议并没有这种要求。虽然在绝大多数邮件服务器的实现中都会表现如上面描述,但是如果你想故意逃避被流量检测程序还原你的邮件通信,你完全可以手动 telnet 上去,然后一个字符一个字符地发送,使 mailfrom 分散在多个包中。

    此外还会有数据包乱序重传丢包等情况。

    所以上面的假设是不完整的。遇到特殊情况会解析失败。

    TCP 重组

    为避免上述的的缺点,需要对 TCP 作重组,也就是按照 TCP 协议来把数据还原成原始发送和接收的状态。给解析工作提供一个完整准确简洁的视角。重组模块把丢包重传乱等 TCC 层的问题序屏蔽掉。解析器看到的数据不是数据包而是和邮件服务器客户端看到的一样,是一条流。

    重组的方式有个简单办法。可以把链接的数据包都保存下来等待链接结束,然后按照序列号的顺序放到一个 buff 中。然后提交给解析器在这个 buffer 中解析邮件协议。就好像处理一个文件一样。

    这样的实现最简单直接。但是这样会有一些问题:

    • 一是必须等待链接结束才可以开始解析,因为如果只有部分不完整的数据解析器无法工作,buffer 的结束边界可能正好在 mailfrom 这个命令的中间,解析器会中途失败或者需要重复扫描。

    • 再一个就是这样会需要很多的内存。如果流量处理程序需要处理大量链接,那内存消耗会无法接受。

    • 还有一个问题,就是等链接结束才开始解析,如果需要根据提取出来的字段作出针对链接的动作(比如阻断),为时已晚。

    所以需要更合适的重组方式。

    流式重组和解码

    如果可以不缓存所有数据等到链接结束,边收数据包,边重组,边解码,边释放数据包,把收到的数据及时消耗掉,那就可以避免上面的缓存完整链接占用太多内存的问题。

    找一个简单的协议考虑一下这种方式,未必不可行。要说简单的协议没有比 SMTP 更合适的了,毕竟它的名字就叫简单邮件协议。最基本的,这个协议就是以\r\n 结束的行为单位。构造命令,邮件头和邮件内容。如果我们在收到完整的一行的数据后就及时把这一行消耗并释放掉。那就不需要缓存所有数据,最多只需要缓存一个不完整的行就可以了。而且这个行的字符数有限,比如 78 。其他基于文本的协议也类似,其他二进制结构的协议可以对比 TCP/IP 的头,也都是固定大小的结构体。总之,并不需要缓存完整的流才能开始解析,只需要缓存最小的不完整的一个单位(一行,或者一个结构体大小)就可以开始协议解析了。解析完成一行,立刻释放这一行。这样就不会占用太多的内存。并且可以实时解析提取数据,立刻根据数据作出动作。前面方式的缺点都可以避免。

    SMTP 的例子如下:

    220 smtp.qq.com Esmtp QQ QMail Server EHLO ABC01234567 250-smtp.qq.com 250-PIPELINING 250-SIZE 73400320 250-STARTTLS 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN 250-MAILCOMPRESS 250 8BITMIME AUTH LOGIN 334 VXNlcm5hbWU6 dXNlcjEyMzQ1QGV4YW1wbGUxMjMuY29t 334 UGFzc3dvcmQ6 MTIzNDU2Nzg= 235 Authentication successful MAIL FROM: <[email protected]> SIZE=300 250 Ok RCPT TO: <[email protected]> 250 Ok DATA 354 End data with <CR><LF>.<CR><LF> Date: Mon, 27 Jun 2022 17:01:55 +0800 From: "[email protected]" <[email protected]> To: =??B?wO60urvU?= <[email protected]> Subject: biaoti X-Priority: 3 X-Has-Attach: no X-Mailer: Foxmail 7.2.19.158[cn] Mime-Version: 1.0 Message-ID: <[email protected]> Content-Type: multipart/alternative; boundary="----=_001_NextPart572182624333_=----" This is a multi-part message in MIME format. ------=_001_NextPart572182624333_=---- Content-Type: text/plain; charset="" Content-Transfer-Encoding: base64 aGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRk ZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRk ZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRk ZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkaGVsbG8gZGRkZGRkZGRkZGRkZGRkZGRkDQoNCg0K DQo= ------=_001_NextPart572182624333_=---- Content-Type: text/html; charset="" Content-Transfer-Encoding: quoted-printable <html><head><meta http-equiv=3D"content-type" cOntent=3D"text/html; charse= t=3D"><style>body { line-height: 1.5; }body { font-size: 14px; font-= yle></head><body>=0A<div><span></span>hello dddddddddddddddddd<span style= =3D"#b5c4df" size=3D"1" align=3D"left">=0A<div><span></span></div>=0A</bod= y></html> ------=_001_NextPart572182624333_=------ . 250 Ok: queued as QUIT 221 Bye 

    重组的实现方式

    既然可以基于行的方式来实现流式重组和解码,那可以为此设计一个重组的实现。目的是为解析器一行一行地提供数据,供解析器使用。那只需要提供这样一个 API:

    get_line(node, line, len)

    其中 node 就是这条链接所在流表的节点,前面说了,我们可以在流表的节点中保存本链接相关的数据。line 就保存在这里。line 是完整一行的数据,len 是这一行的长度。这个 API 如果到来的数据包中不足以凑成一个完整的行,那就返回-1 ,如果凑够了就返回 0 。这样,就给解析器提供了一个行数据的视角,它屏蔽了 TCP 层的麻烦事儿。

    当然,它内部在数据包乱序的情况下仍然需要缓存数据包,这是无法避免的。每次调用这个函数,就从数据包中 copy 数据,直到\r\n 结束。如果数据包被读完,就立刻释放掉这个数据包。如果当前数据不足,就返回失败,等到下次数据包到来被调用。同时 node 上保存着不完整的 line 。这样就不需要缓存整个链接的数据,仅需要占用一个 line 大小的内存即可。根据序列号对数据包排序之类自然也是必须,不必细说。

    这样,一个 API ,就解决了流式重组流式解码的关键问题...

    参考:protolens@giteeprotolens@github

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1378 人在线 &nbp; 最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 16:52 PVG 00:52 LAX 09:52 JFK 12:52
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86