Showing posts with label libpcap. Show all posts
Showing posts with label libpcap. Show all posts

01 November, 2007

Snort Performance and Memory Map Pcap on RHEL

I previously wrote about installing Phil Wood's memory map enabled libpcap as an academic exercise on my home network. As Victor Julien pointed out to me, Snort in inline mode will be using ip_queue rather than the libpcap interface to the kernel. However, I have actually been using mmap libpcap with Snort in IDS mode for quite a while to help reduce packet loss monitoring fairly high bandwidth connections. In testing, I have been able to consistently run Snort in IDS mode and a flow_depth of zero without packet loss on a link doing up to 80Mb/s. Admittedly, this is on pretty high end hardware but it is much better performance than Snort with the regular libpcap. By tuning Snort, like setting flow_depth to something more sensible than zero and disabling rules that are bad for performance, it is easy to see how Snort could be used to monitor even busier links.

There are other ways to increase Snort performance, too. One is using PF_RING. Richard Fifarek has a good write-up about setting up PF_RING with Red Hat Enterprise Linux 4. Maybe I'll get around to testing PF_RING under the same circumstances as I use mmap libpcap, but I'd love to see comments from those that have done it already. I have seen a few comparisons, but not recently. The documentation for PACKET_MMAP, which can be found in the Linux kernel source, has more to say about packet capture performance.

It's fine to use PACKET_MMAP to improve the performance of the capture process, but it isn't everything. At least, if you are capturing at high speeds (this is relative to the cpu speed), you should check if the device driver of your network interface card supports some sort of interrupt load mitigation or (even better) if it supports NAPI, also make sure it is enabled.
I haven't had a chance to play with NAPI yet, but for anyone that is interested there is a NAPI_HOWTO.txt, also in the documentation section of the Linux kernel source.

One last way to improve performance is to use an architecture-specific compiler when building Snort. Although I'm not sure about other architectures, using the Intel compiler for some Intel hardware was mentioned as one of the best ways to improve performance when someone asked a SourceFire employee at Shmoocon a couple years ago about improving Snort performance.

Installing the modified libpcap and reinstalling all the software that depends on it is fairly simple on RHEL. In this case, I'm using RHEL5. Before installing the new libpcap, I stopped any processes that depended on Red Hat's official libpcap package. I removed the official Red Hat libpcap package and any other RPMs that depended on it.
rpm -e libpcap tcpdump
Then I installed the new libpcap.
tar xvzf libpcap-0.9x.20070528.tar.gz
cd libpcap--0.9x.20070528
./configure
make
make install
Now I can go ahead and reinstall the other software using the new libpcap. Just for kicks, the following installs libnet so I can enable flex-resp support even though I don't consider flex-resp very useful in production. Better to just put the box inline if you really need to stop traffic. TCP resets or ICMP unreachable messages leave something to be desired.
cd /usr/src/Libnet-1.0.2a
./configure --prefix=/usr/local/libnet
make
make install

cd /usr/src/tcpdump-3.9.8/
make clean
./configure
make
make install
The following configure statement for Snort should work with 2.6.1.5 or 2.8.0, but I think the --enable-stream4udp is actually now a default for 2.8.0 while it was not for 2.6.x.x.
cd /usr/src/snort-2.8.0
make clean
./configure --without-mysql --without-postgresql --without-oracle
--without-odbc --enable-dynamicplugin --enable-flexresp --enable-stream4udp
--enable-perfprofiling --with-libnet-libraries=/usr/local/libnet/lib
--with-libnet-includes=/usr/local/libnet/include
make
make install
I'm using sancp for session data:
cd /usr/src/sancp-1.6.1/
make clean
make
./install.sh
Finally, I need to set PCAP_FRAMES to a value that the system can use. Finding the maximum can be trial and error, but here are some examples how to set it. One is to set it for each individual application at startup. For instance, sancp doesn't seem to like to use PCAP_FRAMES, so I put the following in the sancpd init script:
export PCAP_FRAMES=0
On the other hand, Snort in IDS mode or packet logging mode can benefit a lot from setting PCAP_FRAMES. For instance,
export PCAP_FRAMES=65535
As I said, it may take experimentation to find the maximum value or the value that results in the best performance. For something like tcpdump, you might want to create an alias something like:
alias tcpdump='PCAP_FRAMES=65535 tcpdump'

08 September, 2007

Transparent Bridging, MMAP pcap, and Snort Inline

I use Snort and the Sguil Analyst Console for NSM, but there is always room to experiment and/or improve. Up to this point, I have used Snort either on mirrored (SPAN) ports or with a network TAP, both common configurations. After finally getting a second-hand CPU and motherboard to replace a dead CPU, I had a spare system to set up Snort inline at home.

The upgrade from Snort 2.4.x to 2.6.x.x was quite taxing on performance, so I decided it was also time to play with Phil Wood's MMAPped libpcap. The modified libpcap will make drastically fewer system calls when compared to the standard libpcap sniffing on a busy network. Although my home network certainly isn't high bandwidth, I wanted the experience of setting up Snort with the Phil Wood's modified version of libpcap. Since I actually did all this many months ago and am just now posting about it, I can say that I have seen a huge performance improvement when going from the standard libpcap to Phil Wood's libpcap in high bandwidth environments.

How would I implement Snort Inline on a home network? The two choices were to replace one of my routers with a BSD or Linux system configured as a router, or to set up Linux as a transparent bridge. For those that prefer FreeBSD, you would have to configure it as a router since the bridge code in FreeBSD does not support the ipfw divert socket. I am not familiar enough with other BSD versions to say whether their bridge code is the same or not.

I much preferred a bridge rather than a router since it would avoid the time-consuming process of reconfiguring my network topology. This meant that I had to use Linux, and my distribution in this case is Slackware-current. The process should not be much different for any distribution.

Installing Software

Because plugging in an untested bridge between my LAN and the Internet could interrupt my connection, I decided it would be easiest to get and install all the software prior to configuring the bridge and putting it inline.

My first step was to install the modified libpcap, which needs either flex and bison, or yacc. This was essentially a freshly built Slackware system and I didn't have them installed, so I used swaret to install the packages.

swaret --install flex
swaret --install bison
I was now ready to install libpcap.
cd /usr/src/
wget http://public.lanl.gov/cpw/libpcap-current.tar.gz
tar xvzf libpcap-current.tar.gz
ln -s libpcap-0.9.20060417 libpcap
cd libpcap
./configure
make
make install
Snort will need the header files from libpcap and the install did not copy them anywhere, so I manually copied the files to /usr/include/. Another option would be to create a link to the files in the include directory.
cp /usr/src/libpcap/pcap.h /usr/include/
cp /usr/src/libpcap/pcap-bpf.h /usr/include/
cp /usr/src/libpcap/pcap-namedb.h /usr/include/
Because this is a modified libpcap, all the software that depends on libpcap must also be compiled against the version I just installed. I will definitely be using tcpdump when I test the bridge.
wget http://www.tcpdump.org/daily/tcpdump-current.tar.gz
tar xvzf tcpdump-current.tar.gz
ln -s tcpdump-2007.01.07 tcpdump
cd tcpdump
./configure
make
make install
Now I could test that tcpdump worked with the PCAP_FRAMES option available because of the modified libpcap. For some reason, perhaps because of my kernel version, PCAP_FRAMES=max did not work but I was able to use it by manually setting the value. I was able to bump the value of PCAP_FRAMES quite high, above 300000, before it resulted in errors. I have yet to determine what that really means for performance. Here are two commands I used to show that the newly installed tcpdump worked with the modified libpcap.
PCAP_FRAMES=65535 PCAP_VERBOSE=1 PCAP_TO_MS=0 PCAP_PERIOD=10000 /usr/local/sbin/tcpdump \
-i eth0 -s 1514 -w /dev/null -c 100

PCAP_FRAMES=65535 /usr/local/sbin/tcpdump -v -i eth0
Snort needs libnet-1.0.2a when configured with --enable-inline, so I had to install libnet first.
tar xvzf libnet-1.0.2a
cd libnet-1.0.2a
./configure
make
make install
Finally, install Snort 2.6.x.x. (Note: Since this document was written quite a while ago, there are quite a few newer versions of Snort available). Another alternative to using the --enable-inline option with mainline Snort is to download snort_inline, which is maintained by William Metcalf and Victor Julien. There are a number of added features and conveniences when using snort_inline, as highlighted on Victor's blog. However, I used mainline Snort in the following example.
tar xvzf snort-2.6.1.2.tar.gz
cd snort-2.6.1.2
./configure --enable-dynamicplugin --enable-inline
make
make install
I tested snort with -V to check that it would start and was compiled to work inline. It shows that Snort was configured with the inline option.
snort -V

,,_ -*> Snort! <*-
o" )~ Version 2.6.1.2 (Build 34) inline
'''' By Martin Roesch & The Snort Team: http://www.snort.org/team.html
(C) Copyright 1998-2006 Sourcefire Inc., et al.

Configuring Linux for Transparent Bridging

Configuring the bridging is fairly simple. The only module I had to manually insert was ip_queue. Other modules that may be needed are ip_tables, iptable_filter and bridge.

In this case, eth0 is my separate management interface, I named the bridge interface bridge0, and the physical interfaces joining bridge0 were eth1 and eth2. The bridge device can be configured with an IP address if you do not want to use a separate NIC for management. In either case, make sure to secure the management NIC on your Snort box, for example limiting connections to the management IP so only source IP addresses in your private IP space are allowed to connect. Here, I created the bridge interface, added eth1 and eth2 to it, and brought them up:
/sbin/brctl addbr bridge0
/sbin/brctl addif bridge0 eth1
/sbin/brctl addif bridge0 eth2
/sbin/ifconfig eth1 up
/sbin/ifconfig eth2 up
/sbin/ifconfig bridge0 up
After some iptables configuration, bridge0 should work. Assuming the system is dedicated to being a bridge running Snort Inline, the only addition necessary to make bridging work is the following:
iptables -I FORWARD -o bridge0 -j ACCEPT
Now bridge0 should be ready to pass packets.

Once the bridge is connected, iptables can be used to show packet statistics and confirm that the bridge is forwarding. You can also use tcpdump -v -i bridge0 to confirm that traffic is passing if you skip ahead to installing libpcap and tcpdump prior to plugging in the bridge.
iptables -vL
--snip--
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
527 168K ACCEPT all -- any bridge0 anywhere anywhere
--snip--
The bridge is seeing packets! tcpdump showed that they were more than just broadcast packets as I accessed the Internet through the bridge.
PCAP_FRAMES=65535 /usr/local/sbin/tcpdump -v -i bridge0
tcpdump: WARNING: bridge0: no IPv4 address assigned
tcpdump: listening on bridge0, link-type EN10MB (Ethernet), capture
--snip--
57 packets captured
57 packets received by filter
0 packets dropped by kernel

Testing Snort Inline

Finally, I'm ready to configure and test Snort Inline. I am not going to cover Snort configuration, but I did write one test rule to put in local.rules and disabled all the other rule sets in snort.conf. The following rule should drop any outbound connection on the HTTP_PORT set in snort.conf.
drop tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Test rule outbound HTTP"; \
classtype:misc-activity; sid: 3000000;)
Now I run Snort. The -v will print packets to the console so I can confirm that snort is seeing the traffic and the -Q tells snort to accept input from the iptables queue.
/usr/local/bin/snort -Qvc /etc/snort/snort.conf -l /data
Note that I forgot to add the PCAP_FRAMES value. In production on a busy network, I would add it permanently to my environmental variables and/or to my init scripts for Snort so it would always take advantage of Phil Wood's libpcap.

I add the necessary rule to iptables. I don't want to risk losing all connections by queueing everything, so I just queue port 80. This is what the line in my iptables-save file looks like:
-A FORWARD -i bridge0 -p tcp -m tcp --dport 80 -m state --state NEW -j QUEUE
I try to browse to a web site and get the following alert in /data/alert:
[**] [1:300000:0] Test rule outbound HTTP [**]
[Classification: Misc activity] [Priority: 3]
01/11-22:22:24.458394 xx.xx.xx.xx:60813 -> 66.35.250.209:80
TCP TTL:63 TOS:0x0 ID:52831 IpLen:20 DgmLen:60 DF
******S* Seq: 0xE79DA525 Ack: 0x0 Win: 0x16D0 TcpLen: 40
TCP Options (5) => MSS: 1460 SackOK TS: 604992578 0 NOP WS: 2
Everything is working. Now I have to get everything ready for production by fully configuring and tuning Snort. Once that is done, I will queue all traffic except port 22. Queuing port 22 could result in not being able to connect using SSH if the Snort process were to die or had to be restarted. If snort-inline is not running, all queued traffic is effectively dropped since Snort is required to pass the traffic from the queue back to iptables.