How to accelerate Suricata, Bro, Snort with PF_RING FT

Posted · Add Comment

In a previous post we discussed the advantages of using specialized adapters featuring flow offload in hardware for accelerating IDS applications. What we have learnt is that IDSs are typically CPU-bound applications, and this is mainly caused by the thousands of rules that need to be evaluated for every single packet (of course in addition to packet capture). This is the case of Suricata, Bro, Snort and other IDS/IPSs as well security applications. More than 2/3 of the Internet traffic is multimedia traffic (mostly video, social networks and music streaming), consisting of a few flows, well-known as elephant flows, carrying a lot of data. This is for example the case of Netflix and Youtube, that is the typical traffic an IDS doesn’t really care about. The same applies to encrypted traffic. Discarding elephant flows is becoming a common yet effective practice for reducing the amount of traffic an IDS/IPS needs to inspect, dramatically reducing packet loss and improving the system performance.

This is why native bypass support has been added to Suricata: a user can write signatures using the bypass keyword to explicitly tell Suricata to skip all packets for the matching flows. In most cases Suricata is using eBPF (as an alternative to local bypass, which is less efficient as packets need to be captured and processed by Suricata, before being discarded) for shunting elephant flows, this means that the application is injecting filtering rules (5-tuples) in kernel space as soon as an elephant flow is detected. This approach has some limitations:

  1. It requires the user to write a Suricata ruleset able to detect all multimedia protocols and bypass matching flows.
  2. Packet parsing is not flexible as eBPF programs cannot loop (it does not work with encapsulations, including vlan and QinQ).
  3. It cannot keep flow state (making it complicated to handle flows expiration).

Last month we introduced PF_RING FT, a new framework supporting flow-processing applications in the flow classification activity, implementing a highly optimized flow table with native support for L7 protocol detection and filtering/shunting capabilities. The L7 filtering engine provided by PF_RING FT can also be used for accelerating Suricata, Bro, Snort with little effort. Since PF_RING FT in already part of PF_RING, if you are using PF_RING or Libpcap-over-PF_RING as capture library, no additional change or recompilation is needed to the application in order to use it. This means that it is possible to leverage on the filtering capabilities of PF_RING FT to filter out multimedia (or any other meaningless) traffic or shunt flows just creating a simple configuration file where you can simply list the application/protocol names: PF_RING FT is based on the nDPI Deep Packet Inspection library for protocols detection, you can specify all the protocols detected by nDPI!

Running FT with Suricata

In this post we will show how to use PF_RING FT to accelerate Suricata in IDS mode, filtering out multimedia traffic including Youtube, Netflix and Spotify.

First of all we need to compile Suricata on top of PF_RING. PF_RING should be installed first:

cd ~
git clone https://github.com/ntop/PF_RING.git
cd ~/PF_RING/kernel
make && sudo make install

cd ~/PF_RING/userland/lib
./configure && make && sudo make install

Then we can install Suricata enabling the PF_RING capture module:

cd ~
git clone https://github.com/OISF/suricata
cd ~/suricata
git clone https://github.com/OISF/libhtp
./autogen.sh
LIBS="-lrt" ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
  --enable-pfring --with-libpfring-includes=/usr/local/include \
  --with-libpfring-libraries=/usr/local/lib
make
sudo make install
sudo ldconfig

sudo make install-conf
sudo make install-rules

We can make sure that PF_RING support is enabled in Suricata with the command below:

suricata --build-info | grep PF_RING
PF_RING support:                         yes

As we said PF_RING FT is already part of PF_RING, however in order to be able to detect and filter L7 protocols, we need to install nDPI:

cd ~
git clone https://github.com/ntop/nDPI.git
./autogen.sh
make && make install

Now we need to create a configuration file like the one below, listing all the L7 protocols that we want to discard or shunt (in this case we need to specify the number of packets to forward per flow before discarding them):

cat /etc/pf_ring/ids-rules.conf
[filter]
YouTube = discard
Netflix = discard
Spotify = discard

[shunt]
SSL = 10

At this point we are able to run Suricata. All we need to do to enable L7 filtering is setting the PF_RING_FT_CONF environment variable with the path of the configuration file we created with the filtering rules:

PF_RING_FT_CONF=/etc/pf_ring/ids-rules.conf suricata --pfring-int=zc:eth1 -c /etc/suricata/suricata.yaml

Validation

In order to validate this work, we used a huge PCAP file (almost 10 GB) with mixed internet traffic, and we replayed the PCAP file using our disk2n application at full 10 Gigabit. We ran Suricata both in a standard configuration (no changes have been made to the default suricata.yaml), with PF_RING FT configured to filter out all meaningless data (NetFlix, Youtube, Spotify, Google, Facebook, SSL). In both cases we used PF_RING ZC drivers for optimal capture performance, in order to reduce the packet capture bottleneck and avoid any noise affecting the results.

In the first configuration Suricata dropped 5.6 Mpkts out of 7.06 Mpkts transmitted (79.4% of packet loss), while in the second configuration, with PF_RING FT enabled, Suricata dropped just 0.56 Mpkts (7.9% of packet loss), after 4.9 Mpkts have been pre-filtered by FT. This looks like a huge performance improvement, with minimal effort!

Have fun with PF_RING FT!