5
31
2017
7

换用 Rust 解析 pcap:快了1000倍!

本文来自依云's Blog,转载请注明。

前天手上有个VPS的提供商发来通知,说VPS在攻击别人的80端口,被第三方投诉了-_-|||

我跑上去看了好久,啥也没发现。进程列表、登录日志、网络使用、各服务我能找到的日志都检查了一遍,也跑了遍 dpkg --verify,啥也没发现。没办法,我就留了句 tcpdump 命令,看看能不能抓到那些恶意流量:

sudo tcpdump -vv -s0 -w port80.log '(dst port 80 and src host 123.456.789.0) or (src port 80 and dst host 123.456.789.0)'

盯了好久,一直只看到有零星的正常访问。

就这么放了一天。第二天想起来的时候过去一看,哇塞,抓到了 2.1G 的包!看来真出问题了。先分析一下得到的 pcap 文件吧。

这么大的 pcap,自然不能拿 Wireshark 打开了。我知道 scapy 能够读取 pcap,于是用它读取 pcap,收集另一方的 IP 地址,看看流量到底都去哪里了。代码很简单,20多行。跑起来~progress 告诉我需要半小时……

于是半小时过去了。我能看到它访问了不少IP,很多是意料之外的。我就想,这些流量是什么时候发生的呢?不过我可不想再花半小时等结果了。然后再想得到点别的数据又得半小时。而且 Python 这种动态类型的语言,稍微复杂一点之后就容易抛异常。说不定快跑出结果的时候,抛个异常出来,前边就全白跑了……

所以就试试 Rust 啦。去 docs.rs 上一搜,还有好几个可以解析 pcap 的库呢。那就第一个吧,叫「pcap」的这个。程序写起来也挺容易的,甚至代码行数都跟 Python 版相仿。时间的处理也是用了一个之前没用过的库「chrono」。并没有花多长时间,直接在文档里找到我需要的功能,然后编译通过就成了 O(∩_∩)O~

extern crate pcap;
extern crate chrono;

use std::collections::BTreeMap;
use chrono::prelude::*;

fn main() {
  let mut capture = pcap::Capture::from_file("../port80.log").unwrap();
  let mut distribution = BTreeMap::new();
  while let Ok(pkt) = capture.next() {
    let t = pkt.header.ts.tv_sec;
    let by_hour = t / 3600 * 3600;
    let dt = Local.timestamp(by_hour, 0);
    *distribution.entry(dt).or_insert(0) += 1;
  }

  for (t, c) in distribution {
    println!("{}: {:8}", t.format("%Y-%m-%d %H:%M"), c);
  }
}

然后花了几秒编译出来优化版本的程序,跑起来~然后我切换到另一个 shell 去跑 progress。啥,没找到进程?再回来一看,哦哦,已经跑完了!只花了一两秒!

这是一千倍的差别啊!虽然两个程序所做的事情并不一样,比如 Python 版用的 scapy,实际上会把整个网络包的各层协议都给解析了,而不像 Rust 版只解析了 pcap 的记录头。但是我又没有别的选择,就像我也不能让 Python 别管引用计数一样。

对于这种小任务,Python 还是强在对少量数据的交互操作,比如 Jupyter Notebook 就很强大。而数据量一旦大起来,就是 Rust 的天下了 :-)

Category: 编程 | Tags: Rust tcpdump | Read Count: 18387
laixintao 说:
Jun 01, 2017 09:37:05 AM

那么恶意流量到底是怎么回事?

Tom 说:
Jun 01, 2017 02:25:29 PM

+1表示没看到恶意流量是咋回事感到很难受

EaiLFly 说:
Jun 02, 2017 08:51:23 AM

+1 表示大喘氣是不道德的

zodiacg 说:
Jun 03, 2017 03:53:57 PM

python的几个pcap处理库都接触过…都有这样那样的问题…

rust到底还是编译型吧,想跟python这种比交互操作还是有点难

x u b o y i n g 说:
Dec 03, 2017 04:49:45 PM

你的python库解析的太多了,pcap的文件格式很简单,
typedef struct pcaprec_hdr_s {
guint32 ts_sec; /* timestamp seconds */
guint32 ts_usec; /* timestamp microseconds */
guint32 incl_len; /* number of octets of packet saved in file */
guint32 orig_len; /* actual length of packet */
} pcaprec_hdr_t;

https://wiki.wireshark.org/Development/LibpcapFileFormat

用类似pack的方法解出内容层,排除以太网层有或无vlan的可能性后,指向三层的目标ip(v4)地址头取4字节一下就好了,用pypy或或者numba加速应该是飞快的。

Avatar_small
依云 说:
Dec 04, 2017 12:56:53 AM

是啊,我也知道它解析的太多了。但总不能每次想解析点什么就去自己写个定制的 parser 啊。当然这个案例里我可以去优化,不过我就是想练习一下 Rust 嘛。

Python 的个性就是这样,方便好用,但是不那么关注性能,没人给你一步步解析的接口。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com