Netis Packet-Agent : 一种云环境网络流量镜像的通用解决方案(V2.0)

1,417 阅读5分钟

0x00 背景

目前,最流行的网络监控和故障分析工具是SPAN(Switch Port Analyzer),也就是端口镜像。传统网络数据分析会在交换机上配置网络数据镜像, 将Packet复制后发送到目标机器,实现网络流量镜像的功能。

而在云平台上,目前网络数据采集还没有统一的方案。针对私有云平台,目前有流表数据包复制采集、在hypervisor上监听采集、vmware平台分布式虚交换机配置采集、libpcap抓包采集等方案。

对于vmware平台分布式虚交换机配置采集的方案,性能较好,不占用客户机资源,但其属于商业产品,且只适用于购买vmware私有云用户;而在hypervisor上监听采集,目前有产品开发,性能较好,但只适用于OpenStack私有云;采用OVS流表方案,优势是免费,不占用客户机资源,但是配置复杂,且只能用于OpenStack私有云。

因此,开发基于libpcap + GRE转发的应用,或许是云平台目前最优的网络流量镜像方案。其使用简单、开源、适用于各类公有云和私有云,只是需要在客户机部署接收工具而占用客户机CPU、内存、网络资源。

0x01 GRE技术原理

GRE:通用路由封装(Generic Routing Encapsulation)定义了在任意一种网络层协议上封装任意一个其它网络层协议的协议。 通过对某些网络层协议(如IP 和IPX)的数据报文进行封装,使这些被封装的数据报文能够在另一个网络层协议(如IP)中传输。

GRE采用了Tunnel(隧道)技术,是VPN(Virtual Private Network)的第三层隧道协议。 Tunnel 是一个虚拟的点对点的连接,提供了一条通路使封装的数据报文能够在这个通路上传输,并且在一个Tunnel 的两端分别对数据报进行封装及解封装。一个X协议的报文要想穿越IP网络在Tunnel中传输,必须要经过加封装与解封装两个过程。

标准的GRE的封装和报头格式如下:

前4字节是必须出现的。第5~20字节将根据第1字节的相关bit位信息,可选出现。例如,如果其中K比特设置为1,则密钥部分的4字节会出现在GRE头部。此时头部总长8字节。需要注意的是,GRE头部的长度将影响Tunnel口的mtu值。

在思科的网络设备中,有一种专有的网络流量镜像格式ERSPAN(Encapsulated Remote Switch Port Analyzer),即在SPAN的基础上扩展了encapsulated remote的特性。ERSPAN封装格式是基于GRE,可应用于IPv4及IPv6网络上。目前有三种类型:ERSPAN Type I、ERSPAN Type II 及ERSPAN Type III。其中ERSPAN Type I格式因为可扩展性差,已经被废弃。三种类型的头格式如下:

ERSPAN的几个要点:

  • IP头上层协议字段统一为GRE(47);
  • Type I仅包含必选GRE头,GRE协议字段和Type II 相同(0x88BE),flag全部为0。总长仅4字节(flag),所以比Type II更紧凑,但由于缺乏扩展性,目前已被废弃;
  • Type II和Type III包括GRE头部和ERSPAN头。GRE头部相同,都包含且只包含sequence可选字段。其中Type III的协议值为0x22EB.

有关ERSPAN格式的详细文档,请参考 tools.ietf.org/html/draft-….

0x02 packet-agent简介

Netis Packet Agent是一个用于解决如下问题的开源项目:设备A上抓取的数据包,之后在设备B上使用分析。在很多时候,当你希望监控网络的流量,但是并没有可用的设备,例如:

物理环境中不存在TAP和SPAN设备。 虚拟环境中,Virtual Switch Flow Table不支持SPAN功能。 因此,该项目提供一套低开销但是高性能的抓包工具,用于应对上述困难。

pktminerg是第一个发布的工具。该工具可以轻松地在网卡上抓数据包,用GRE头进行封装并发送到远端的设备,来进行数据包监控和分析。

此外,还有另外3个工具:

  • pcapcompare用于比较两个pcap文件
  • gredump根据特定的过滤规则抓取GRE数据包,并存储为pcap文件。
  • gredemo是一个demo应用程序,可以从pcap文件读取数据包,然后把它们发送到远端网卡。这个程序只能通过源代码编译生成。

目前,packet-agent已经支持了CentOS 6/7、Redhat 7、SUSE 12、Ubuntu 18.04、Windows 7/8/10的x86_64系统。当然,不仅仅是物理机可以运行,云环境、docker容器同样支持运行packet-agent工具集。

下面是一些简单的使用方法:

# Capture packet from NIC "eth0", encapsulate with GRE header and send to 172.16.1.201
pktminerg -i eth0 -r 172.16.1.201

# Specify cpu 1 for this program with high priority to avoid thread switch cost.
pktminerg -i eth0 -r 172.16.1.201 --cpu 1 -p

# compare 2 pcap files
pcapcompare --lpcap /path/to/left_file.pcap --rpcap /path/to/right_file.pcap

# Capture packet from NIC "eth0" and save them to gredump_output.pcap
gredump -i eth0 -o /path/to/gredump_output.pcap

# Capture packet from NIC "eth0", do not set DF flag
pktminerg -i eth0 -r 172.16.1.201 -M dont

packet-agent默认的封装格式为带key的标准GRE头部封装。通过指定可选的插件扩展,用户能够使用其他协议封装数据包。目前支持的扩展有:

  • proto_gre:支持key/sequence的启用禁用,sequence初始值及key值设置。
  • proto_erspan_type1:ERSPAN Type I封装。
  • proto_erspan_type2:ERSPAN Type II封装。支持vlan/sequence的启用禁用,sequence初始值及vlan值设置。
  • proto_erspan_type3:ERSPAN Type III封装。支持vlan/sequence/timestamp的启用禁用,sequence初始值及vlan值设置。目前仅支持必选头的配置。

扩展目前处于实验阶段。仅支持linux平台。

使用实例:


# 插件以动态库的形式存在。
# 配置字段说明(下面的例子已经包含了所有的字段)
# ext_file_path:插件文件名(.so文件路径),支持相对/绝对路径。
# entry:插件入口函数,动态加载时被调用。第三方插件开发者可以指定自己的入口函数。
# ext_param:插件自定义的参数。ext_param内的字段可以不配置,此时采用默认值(false / 0)
#     use_default_header:头部字段仅包括必选部分,可配值为0。如果设置为true,其余字段无效。
#     enable_vlan/vlan/enable_sequence/sequence_begin/enable_timestamp/enable/key/key:顾名思义。不同的插件字段不同。

# proto_erspan_type3 
JSON_STR=$(cat << EOF
[
    {
        "ext_file_path": "libproto_erspan_type3.so",
        "ext_params": {
            "use_default_header": false,
            "enable_vlan": true,
            "vlan": 1024,
            "enable_sequence": true,
            "sequence_begin": 10000,
            "enable_timestamp": true
        }
    }
]
EOF
)
./pktminerg -i eth0 -r 10.1.1.37 --proto_config "${JSON_STR}"

# proto_erspan_type2 
JSON_STR=$(cat << EOF
[
    {
        "ext_file_path": "/path/to/libproto_erspan_type2.so",
        "ext_params": {
            "use_default_header": false,
            "enable_vlan": true,
            "vlan": 1027,
            "enable_sequence": true,
            "sequence_begin": 10000
        }
    }
]
EOF
)
./pktminerg -i eth0 -r 10.1.1.37 --dump --proto_config "${JSON_STR}"


# proto_erspan_type1
JSON_STR=$(cat << EOF
[
    {
        "ext_file_path": "../libproto_erspan_type1.so",
        "ext_params": {
        }
    }
]
EOF
)
./pktminerg -i eth0 -r 10.1.1.37 --proto_config "${JSON_STR}"


# proto_gre
JSON_STR=$(cat << EOF
[
    {
        "ext_file_path": "libproto_gre.so",
        "ext_params": {
            "use_default_header": false,
            "enable_key": true,
            "key": 3,
            "enable_sequence": true,
            "sequence_begin": 10000
        }
    }
]
EOF
)
./pktminerg -i eth0 -r 10.1.1.36 --proto_config "${JSON_STR}"