tcpdump 抓包显示 toa 源地址

LVS 是个很流行的高性能负载均衡程序。不过因为工作在 3-4 层,对被代理的后端来说,就只能看到 LVS 的源地址,看不到实际的用户来源 IP 地址了。所以 LVS 提供了一个 toa 内核模块,在后端安装后,可以从 TCP 头的扩展段里获取源 IP 地址。不过这只限于应用层面。系统层面的工具比如 netstat,tcpdump 等仍然只能看到 LVS 的源地址,想通过 tcpdump 抓包过滤或者分析实际来源地址就不行了。不过既然在 TCP 头里有这数据我们就还是可以利用。

tcpdump 输出的内容里,如果有 toa 扩展,会多出一截 Unknown Option。其中后面的 32bit 就是实际的源 IP。如

... ack 1562404315, win 29, options [Unknown Option 20030390a0a0101], length 0

按 TOA 的结构:

struct toa_data {
	__u8 opcode;
	__u8 opsize;
	__u16 port;
	__u32 ip;
};

这里的 0a0a0101 就是 10.10.1.1,3039就是源端口 12345。

因为 TCP 头里多了扩展字段,所以 TCP 头中的 data_offset 就会大于 5(words)。用 ((tcp[12] & 0xf0)>>4) > 5 这个条件过滤可以只处理带 toa 头的包。TCP 扩展字段从 20 字节开始。所以可以直接用比如 tcp[24:4]==0x0a0a0101 过滤指定源 IP 的包。

下面这段脚本就会输出发往 1234 端口的实际源 IP 的地址。

sudo tcpdump -nn -l "tcp dst port 1234 and ((tcp[12] & 0xf0)>>4) > 5" 2>/dev/null | \
    awk 'match($0, "Unknown Option ([0-9a-f]+)",a) {print strtonum("0x" substr(a[1],8,2)) "." strtonum("0x" substr(a[1],10,2)) "." strtonum("0x" substr(a[1],12,2)) "." strtonum("0x" substr(a[1],14,2)); fflush()}'

升级 centos 内核到 4.x

centos 发行版是跟随 redhat 发行版的。在内核版本上比较保守。比如 centos 6.x 分支最高是 2.6.32 内核。虽然也会 backport 一些高版本的功能,但是总会需要的功能没有的情况。

不过 centos 的仓库里其实藏着一个 4.x 的内核。

在 centos 仓库里,有一个 centos-release-xen 的包,是 由 Centos、CitrixXen、Godaddy、Rackspace 共同维护的 Xen4CentOS 项目的一部分。

Xen4CentOS
The project, while hosted at centos.org, is a collaboration between the Xen Project, the Citrix Xen open source teams, the CentOS developers, GoDaddy Cloud Operations team, Rackspace Hosting and members of the CentOS QA Team.

这个包中其实并没有 xen 的工具,只是一个内核而已。安装这个包就能将 linux 内核升级到高版本。

yum install centos-release-xen
yum update

重启,然后 uname -r 检查一下就会发现内核版本已经到了比如 4.9.58-29.el6.x86_64