本文主要介绍vpp snort插件的编译及配置使用流程。在编译vpp之前首先需要安装libdaq库。在github上下载最新代码,并按照指导文档进行编译安装libdaq库。
代码语言:javascript复制#下载最新libdaq代码
git clone https://github.com/snort3/libdaq.git
#进入libdaq目录并编译安装。首先需要执行bootstrap脚本生成configue脚本
./bootstrap
#运行configure脚本,并编译安装
./configure
make
make install
接下来直接编译vpp版本,会生成两个snort相关的so库,libdaq_vpp.so.23.10和snort_plugin.so,具体路径如下:
代码语言:javascript复制##1、运行snort客户端时,需要指定libdaq_vpp.so所载的目录。
root@jinsh:~/workspace/vpp-master/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/daq# ls -lt
total 40
lrwxrwxrwx 1 root root 19 Aug 12 04:36 libdaq_vpp.so -> libdaq_vpp.so.23.10
-rw-r--r-- 1 root root 39816 Aug 12 04:35 libdaq_vpp.so.23.10
##2、snort 插件so库 snort_plugin.so
root@jinsh:~/workspace/vpp-master/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/vpp_plugins# ls -lt | grep snort
-rw-r--r-- 1 root root 559128 Aug 12 04:36 snort_plugin.so
运行vpp程序,查询snort插件已经成功加载,并默认启动snort 监听socket,snort listener /run/vpp/snort.sock,等待snort客户端链接。
代码语言:javascript复制root@jinsh:~# vppctl show plugins | grep snort
63. snort_plugin.so 23.10-rc0~135-g09c0e8fac Snort
##并且默认启动snort监听socket,等待snort客户端链接。
DBGvpp# show unix files
FD Thread Read Write Error File Name Description
6 0 0 0 0 socket:[87631] stats segment listener /run/vpp/stats.sock
8 0 0 0 0 socket:[87634] snort listener /run/vpp/snort.sock
9 0 1 0 0 pipe:[87636] DPDK logging pipe
21 0 2 0 0 socket:[87647] cli listener /run/vpp/cli.sock
23 0 0 0 0 socket:[87650] socksvr /run/vpp/api.sock
24 0 18 1 0 socket:[87802] local:1
创建实例,名称为ids-engine,设置队列大小64,创建snort实例默认会创建基于线程数量的eventfd,应该是中断模式使用事件通知机制,还需再研究
代码语言:javascript复制#创建snort实例ids-engine
DBGvpp# snort create-instance name ids-engine queue-size 64 on-disconnect pass
#查询snort实例
DBGvpp# show snort instances
ids-engine [idx:0 sz:8192 fd:27]
#创建snort实例默认会创建基于线程数量的创建eventfd,应该是中断模式使用事件通知机制,还需再研究
DBGvpp# show threads
ID Name Type LWP Sched Policy (Priority) lcore Core Socket State
0 vpp_main 3688 other (0) 1 0 0
1 vpp_wk_0 workers 3692 other (0) 2 0 0
2 vpp_wk_1 workers 3693 other (0) 3 0 0
DBGvpp# show unix files
FD Thread Read Write Error File Name Description
6 0 0 0 0 socket:[87631] stats segment listener /run/vpp/stats.sock
8 0 0 0 0 socket:[87634] snort listener /run/vpp/snort.sock
9 0 1 0 0 pipe:[87636] DPDK logging pipe
21 0 3 0 0 socket:[87647] cli listener /run/vpp/cli.sock
23 0 0 0 0 socket:[87650] socksvr /run/vpp/api.sock
24 0 83 1 0 socket:[87802] local:1
25 0 27 1 0 socket:[88058] local:2
26 1 0 0 0 anon_inode:[eventfd] GigabitEthernetb/0/0 queue 0
30 0 0 0 0 anon_inode:[eventfd] snort dequeue for instance 'ids-engine' qpair 0
32 1 0 0 0 anon_inode:[eventfd] snort dequeue for instance 'ids-engine' qpair 1
34 2 0 0 0 anon_inode:[eventfd] snort dequeue for instance 'ids-engine' qpair 2
snort实例与接口关联,也就是接口 使能snort feature。
代码语言:javascript复制#snort实例与接口绑定,可以指定接口input或output方向,默认两个方向都使能
DBGvpp# snort attach instance ids-engine interface GigabitEthernetb/0/0
#查询snort实例与接口绑定关系
DBGvpp# show snort interfaces
interface snort instance
GigabitEthernetb/0/0: ids-engine
#查询接口featue使能情况
DBGvpp# show interface feat GigabitEthernetb/0/0
Feature paths configured on GigabitEthernetb/0/0...
ip4-output: #output方向使能snort-enq
snort-enq
ip4-unicast: #input 方向使能snort-enq
snort-enq
设置snort模式,默认为中断模式,也可设置为轮询模式polling。
代码语言:javascript复制#snort模式设置,默认中断,可以设置为轮训模式
DBGvpp# snort mode interrupt
#查询snort模式
DBGvpp# show snort mode
input mode: interrupt
接下来就是启动snore客户端:使用libdaq源码中的测试程序,作为snort插件的客户端。选项-d用于指定使用的daq库,只需要填写vpp,不需要完整的文件名(libdaq_vpp.so)。选项-i指定实例名称,即以上创建的ids-engine。选项-m指定daq库的查找目录。
代码语言:javascript复制#先打开snort日志系统,设置debug
DBGvpp# set logging class snort level debug syslog-level debug rate-limit 5000
##启动客户端,并在内核下ping 接口ip地址,数量1个包。可以看到snort客户端显示ping请求和响应报文。
root@jinsh:~/workspace/snort/libdaq/example# ./daqtest -d vpp -i ids-engine -C input_mode=interrupt -m "/root/workspace/vpp-master/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/daq"
[Config]
Input: ids-engine
Snaplen: 1518
Timeout: 0ms (Allowance: Unlimited)
Module Stack:
0: [vpp]
Mode: passive
Variables:
input_mode=interrupt
Packet Count: Unlimited
Batch Size: 16
Default Verdict: pass
Ping Action: Pass
Local MAC Address: 06:2d:e3:7e:56:b3
Snaplen: -1
Message Pool Info:
Size: 256
Available: 128
Memory Usage: 0
Packet 1: Size = 84/84, Ingress = 0 (Group = -1), Egress = 0 (Group = -1), Addr Space ID = 1
IP: 192.168.1.30 -> 192.168.1.33 (84 bytes) (checksum: 50991) (protocol: 1)
ICMP: Type 8 Code 0 Checksum 9911 (56 bytes of data)
Echo: ID 9 Sequence 1
Packet 2: Size = 98/98, Ingress = 0 (Group = -1), Egress = 0 (Group = -1), Addr Space ID = 0
IP: 192.168.1.33 -> 192.168.1.30 (84 bytes) (checksum: 2228) (protocol: 1)
ICMP: Type 0 Code 0 Checksum 9919 (56 bytes of data)
Echo: ID 9 Sequence 1
在系统日志中可以查询到snort客户端连接到vpp的debug日志。并且可以查询到snort 客户端数量是1.
代码语言:javascript复制#查询snort客户端。
DBGvpp# show snort clients
number of clients: 1
#查询到snort clients对应的socket。
DBGvpp# show unix files
FD Thread Read Write Error File Name Description
8 0 1 0 0 socket:[87634] snort listener /run/vpp/snort.sock
25 0 1 5 0 socket:[89211] snort client
DBGvpp#
#日志记录
Aug 14 15:08:52 jinsh vpp[3688]: snort: snort_conn_fd_accept_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_read_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_read_ready: connect instance ids-engine
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_read_ready: connect instance index 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_write_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_write_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_write_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_write_ready: client 0
Aug 14 15:08:52 jinsh vpp[3688]: snort: fd_write_ready: client 0
snort数据平面包括snort-enq和snort-deq两个节点,其中snort-enq类型为internal内部,比如其节点关系有:ip4-input -> snort-enq -> ip4-sv-reassembly-feature。节点snort-deq为入口input类型节点,其下一个节点有error-drop和ip4-lookup等选择。由于snort-deq节点并未支持trace功能,所以我们无法进行trace,后续有时间可以提交一个trace patch。
代码语言:javascript复制00:28:09:747705: dpdk-input
GigabitEthernetb/0/0 rx queue 0
buffer 0x99c80: current data 0, length 98, buffer-pool 0, ref-count 1, trace handle 0x1000000
ext-hdr-valid
PKT MBUF: port 0, nb_segs 1, pkt_len 98
buf_len 2176, data_len 98, ol_flags 0x80, data_off 128, phys_addr 0xca72080
packet_type 0x91 l2_len 0 l3_len 0 outer_l2_len 0 outer_l3_len 0
rss 0x0 fdir.hi 0x0 fdir.lo 0x0
Packet Offload Flags
PKT_RX_IP_CKSUM_GOOD (0x0080) IP cksum of RX pkt. is valid
PKT_RX_IP_CKSUM_NONE (0x0090) no IP cksum of RX pkt.
Packet Types
RTE_PTYPE_L2_ETHER (0x0001) Ethernet packet
RTE_PTYPE_L3_IPV4_EXT_UNKNOWN (0x0090) IPv4 packet with or without extension headers
IP4: a4:83:e7:64:54:70 -> 00:50:56:33:cd:a8
ICMP: 192.168.1.30 -> 192.168.1.33
tos 0x00, ttl 64, length 84, checksum 0xc3cd dscp CS0 ecn NON_ECN
fragment id 0xf34b, flags DONT_FRAGMENT
ICMP echo_request checksum 0x5933 id 11
00:28:09:747732: ethernet-input
frame: flags 0x1, hw-if-index 1, sw-if-index 1
IP4: a4:83:e7:64:54:70 -> 00:50:56:33:cd:a8
00:28:09:747750: ip4-input
ICMP: 192.168.1.30 -> 192.168.1.33
tos 0x00, ttl 64, length 84, checksum 0xc3cd dscp CS0 ecn NON_ECN
fragment id 0xf34b, flags DONT_FRAGMENT
ICMP echo_request checksum 0x5933 id 11
00:28:09:747775: snort-enq
sw-if-index 1 next-index 1
instance 0 qpair 1 desc-index 63 slot 4
desc: buffer-pool 0 offset 40313102 len 84 address-space-id 1
本文参考博客完成snort基本的配置及运行。snort在实现中使用memfd_create共享内存方式实现snort客户端和vpp之间的报文同步。后续再详细阅读代码了解其实现细节。:https://blog.csdn.net/sinat_20184565/article/details/126090371
memfd_create共享内存在dpdk及vpp代码中经常使用,不了解的可以参考一下宋宝华老师文章介绍:https://cloud.tencent.com/developer/article/1551288。