流的定义
流是一系列通过网络中某一观察点的具有相同属性的数据包,属性包括
- 端点:流的起点和终点
- 方向:单向或双向
- 时间粒度:数据包的发送起始时间和终止时间
- 协议层次:包括网络各层协议
NetFlow/IPFIX
协议介绍与关系
Netflow
: 于1996年由思科公司发明,于同年5月注册为美国专利。首先用于网络设备对数据交换进行加速,并同步实现对高速转发的IP
数据流进行测量和统计,经过多年的技术演进,NetFlow
原来用于数据交换加速的功能已经逐步由网络设备中的专用ASIC
芯片实现,而对IP
数据流进行测量和统计的功能也已更加成熟,形成了一种专用流交换技术,NetFlow
已集成到大多数厂商的路由器和交换机内成为流量监测的事实标准,广泛应用于网络管理IPFIX
:全称IP Flow Information Export
,即IP
流信息输出,在 2003 年,Netflow V9
被IETF
组织从 5 个候选方案中确定为IPFIX
标准,作为IP
网络中的流信息测量的标准协议,是网络流量监测的国际标准,是一种针对数据流特征分析、基于模板的格式输出的协议,因此具有很强的可扩展性
协议缺点
netflow
:- 消耗路由器的
CPU
和存储资源,对设备的转发性能有影响 - 流记录的数据量仍然很大,非独立设备,处理能力不足,因此,一般采用
100~1000:1
采样比,监测粒度较粗,损失流量
的细节信息 - 设备本身提供的数据内容有局限性,策略和定制能力相对较差。
NetFlow
功能集成在设备内,软件实现性能差、硬件实现灵活性差,对于大量已部署运行的路由器升级板卡费用高 NetFlow
业务和应用识别主要依赖于TCP/UDP
端口号,无法识别日新月异的业务
- 消耗路由器的
协议系统组成
Exporter
/探测器:用于监听网络数据Collector
/采集器:用于收集从Exporter
输出的网络数据Analysis
/分析报告系统:用于分析从Collector
收集到的网络数据,并产生报告
netflow
数据字段
数据流
- 源
IP
- 目的
IP
- 协议
- 端口
流量统计数据
- 数据流时戳
- 源
IP
地址 - 目的
IP
地址 - 源端口号
- 目的端口号
- 输入接口号和输出接口号
- 下一跳
IP
地址 - 信息流中的总字节数
- 信息流中的数据包数量
- 信息流中的第一个和最后一个数据包时戳 源 AS 和目的 AS
- 前置掩码
- 数据包序号
IPFIX
数据字段
为了较完整的输出数据,IPFIX
缺省使用网络设备的七个关键域来表示每股网络流量,如果不同的 IP
报文中所有的七个关键域都匹配,那么这些 IP
报文都将被视为属于同一股流量
通过记录网络中这些流量的特征,如流量持续时间、流量中报文平均长度等, 我们可以了解到当前网络的应用情况,并根据这些信息对网络进行优化,安全检测,流量计费
- 源
IP
地址 - 目的
IP
地址 TCP/UDP
源端口TCP/UDP
目的端口- 三层协议类型
- 服务类型
Type-of-service
字节 - 输入逻辑接口
协议收集器collector
依赖开源项目goflow2
(golang
项目)
https://github.com/netsampler/goflow2
构建
$ git clone https://github.com/netsampler/goflow2.git
$ cd goflow2
$ make build
# 如果需要静态链接库,可以执行如下
$ CGO_ENABLED=0 make build
会产生一个dist
文件夹,里面包含一个可执行文件dist/goflow2-版本-git-commit-架构
把可执行文件重命名为goflow2
执行监听,可以看到该程序同时支持netflow/sflow
协议采集,监听udp
2055端口收集netflow
协议数据包,保持这个终端不关闭,接下去开始执行协议探测程序
$ ./dist/goflow2
INFO[0000] starting GoFlow2
INFO[0000] starting collection count=1 hostname= port=6343 scheme=sflow
INFO[0000] starting collection count=1 hostname= port=2055 scheme=netflow
协议探测exporter
依赖开源项目softflowd
(c
语言项目)作为流量探测器,可以探测linux
主机物理网口的网卡流量信息,并且按照netflow/ipfix
协议定义封装流量包发送到指定的采集器
https://github.com/irino/softflowd
构建,如下操作会生成可执行文件softflowd
$ git clone https://github.com/irino/softflowd.git
$ cd softflowd
$ autoreconf -if
$ ./configure
$ make
安装到/usr/bin
(这一步可以省略)
$ sudo make install
执行netflow
采集
$ sudo ./softflowd -v 5 -i enp3s0 -t maxlife=1 -n 127.0.0.1:2055 -P udp -D
# 或者
$ sudo ./softflowd -v 9 -i enp3s0 -t maxlife=1 -n 127.0.0.1:2055 -P udp -D
执行ipfix
采集
$ sudo ./softflowd -v 10 -i enp3s0 -t maxlife=1 -n 127.0.0.1:2055 -P udp -D
参数解释
-v
:表示发送netflow
协议版本号,一般是5/9
版本,依据./softflowd --help
输出信息,如下表示,当版本是10的时候,会探测并封装为ipfix
包-v 1|5|9|10|psamp NetFlow export packet version 10 means IPFIX and psamp means PSAMP (packet sampling)
-i enp3s0
: 表示探测当前主机网口enp3s0
的网卡流量,主机网卡可以通过ip a
命令获取-t maxlife=3
: 表示每3秒发送一次netflow
流包,目前softflowd 1.1.0
版本help
命令输出参数是-t timeout=time Specify named timeout
,后期如果maxlife
无效,可以尝试修改为-t timeout=1
-n 127.0.0.1:2055
:表示把探测到的流量数据封装并发送给目的地址为127.0.0.1:2055
的collector
-P udp
: 指定发送给exporter
的传输层协议类型,一般是udp
-D
:debug
模式,保持前端运行并输出日志信息
exporter
程序打印数据
当softflowd
的-v
参数变化时,goflow2 exporter
监听程序打印输出的数据会动态输出不同的类型
-v 5
{
"type": "NETFLOW_V5",
"time_received_ns": 0,
"sequence_num": 4,
"sampling_rate": 0,
"sampler_address": "127.0.0.1",
"time_flow_start_ns": 1692162613180684000,
"time_flow_end_ns": 1692166704180684000,
"bytes": 642,
"packets": 6,
"src_addr": "10.30.2.174",
"dst_addr": "239.192.152.143",
"etype": "IPv4",
"proto": "UDP",
"src_port": 7000,
"dst_port": 7000,
"in_if": 0,
"out_if": 0,
"src_mac": "00:00:00:00:00:00",
"dst_mac": "00:00:00:00:00:00",
"src_vlan": 0,
"dst_vlan": 0,
"vlan_id": 0,
"ip_tos": 0,
"forwarding_status": 0,
"ip_ttl": 0,
"tcp_flags": 0,
"icmp_type": 0,
"icmp_code": 0,
"ipv6_flow_label": 0,
"fragment_id": 0,
"fragment_offset": 0,
"src_as": 0,
"dst_as": 0,
"next_hop": "0.0.0.0",
"next_hop_as": 0,
"src_net": "0.0.0.0/0",
"dst_net": "0.0.0.0/0",
"bgp_next_hop": "",
"bgp_communities": [],
"as_path": [],
"mpls_ttl": [],
"mpls_label": [],
"mpls_ip": [],
"observation_domain_id": 0,
"observation_point_id": 0
}
-v 9
{
"type": "NETFLOW_V9",
"time_received_ns": 1692168027637104030,
"sequence_num": 1,
"sampling_rate": 0,
"sampler_address": "127.0.0.1",
"time_flow_start_ns": 1692162288000000000,
"time_flow_end_ns": 1692167289000000000,
"bytes": 276,
"packets": 6,
"src_addr": "10.30.7.161",
"dst_addr": "224.0.0.18",
"etype": "IPv4",
"proto": "",
"src_port": 0,
"dst_port": 0,
"in_if": 0,
"out_if": 0,
"src_mac": "00:00:00:00:00:00",
"dst_mac": "00:00:00:00:00:00",
"src_vlan": 0,
"dst_vlan": 0,
"vlan_id": 0,
"ip_tos": 192,
"forwarding_status": 0,
"ip_ttl": 0,
"tcp_flags": 0,
"icmp_type": 0,
"icmp_code": 0,
"ipv6_flow_label": 0,
"fragment_id": 0,
"fragment_offset": 0,
"src_as": 0,
"dst_as": 0,
"next_hop": "",
"next_hop_as": 0,
"src_net": "0.0.0.0/0",
"dst_net": "0.0.0.0/0",
"bgp_next_hop": "",
"bgp_communities": [],
"as_path": [],
"mpls_ttl": [],
"mpls_label": [],
"mpls_ip": [],
"observation_domain_id": 0,
"observation_point_id": 0
}
-v 10
{
"type": "IPFIX",
"time_received_ns": 1692168053184893251,
"sequence_num": 25,
"sampling_rate": 0,
"sampler_address": "127.0.0.1",
"time_flow_start_ns": 1692168053000000000,
"time_flow_end_ns": 1692168053000000000,
"bytes": 68,
"packets": 1,
"src_addr": "10.30.6.69",
"dst_addr": "255.255.255.255",
"etype": "IPv4",
"proto": "UDP",
"src_port": 40408,
"dst_port": 60006,
"in_if": 0,
"out_if": 0,
"src_mac": "00:00:00:00:00:00",
"dst_mac": "00:00:00:00:00:00",
"src_vlan": 0,
"dst_vlan": 0,
"vlan_id": 0,
"ip_tos": 0,
"forwarding_status": 0,
"ip_ttl": 0,
"tcp_flags": 0,
"icmp_type": 0,
"icmp_code": 0,
"ipv6_flow_label": 0,
"fragment_id": 0,
"fragment_offset": 0,
"src_as": 0,
"dst_as": 0,
"next_hop": "",
"next_hop_as": 0,
"src_net": "0.0.0.0/0",
"dst_net": "0.0.0.0/0",
"bgp_next_hop": "",
"bgp_communities": [],
"as_path": [],
"mpls_ttl": [],
"mpls_label": [],
"mpls_ip": [],
"observation_domain_id": 0,
"observation_point_id": 0
}