Monday, June 08, 2009

IP Blacklisting Version 2 for Snort 2.8.4.1 available


I found myself with 9 hours to kill on an airplane ride this weekend so I coded up the two features I've been hearing the most for the original IP Blacklisting patch I wrote. The first new feature was to be able to associate a name with a blacklist and have that name produced in the event that Snort outputs. The second feature was to be able to load blacklists from external files so that very large blacklists could be maintained without having to modify the snort.conf file.

Both of these features are now available in version 2 of the patch. Direct loading of the IP address lists from the snort.conf preprocessor directive is no longer supported, you have to use the external files.

Here is a sample directive for snort.conf:


preprocessor iplist: blacklist dshield /etc/snort/dshield.blacklist \
blacklist sourcefire /etc/snort/sourcefire.blacklist \
whitelist /etc/snort/default.whitelist


And here is a sample blacklist file:

# This is a blacklist file, there are many like it but this one is mine
# Comments are supported
10.1.1.0/24 192.168.0.0/16 # I can do inline comments too and put
# multiple CIDR blocks on one line
172.16.16.17/32
172.16.15.14/32 # Whatever you like


As per usual, bug reports and feature requests can be sent directly to me. I still haven't done any performance testing of this code so your mileage may vary. I'd be interested to hear of any comparisons of the performance of this code vs the Emerging Threats blacklist.

Tested on Ubuntu, Fedora and OS X only so far.

You can get the patch here:

http://www.snort.org/users/roesch/code/iplist.patch.v2.tgz



Technorati Tags:
, , , ,



Labels: , , , , ,

Wednesday, May 13, 2009

IP Blacklisting for Snort 2.8.4.1 available


After a discussion on the Snort-users mailing list last week regarding using standard Snort rules to implement Reputation-based IP blocking in Snort (and how badly the performance sucked) I decided to write some code to do it the "right way". The result is the "iplist" preprocessor, a module that supports IP Blacklisting and whitelisting via user-provided lists of known hostile IP addresses.

The internals of the system use the Patricia Trie code from the Snort 3.0 code tree to provide the primary address lookup mechanism. Currently I'm only supporting IPv4 addresses although the P-Trie code supports IPv6 addressing too.

This patch has been applied against Snort 2.8.4.1 only. I've tested
builds on OS X, Ubuntu and Fedora so far. It requires libdnet (or
dumbnet-dev for those of you on Debian-based distros) to build
properly. Check the README file that comes with it for instructions
on patching it into your codebase. It supports inline blocking and
alerting but not Flexresp-style TCP reset session shootdowns.

Have a look and let me know what features you'd like or bugs you find.

This code is purely EXPERIMENTAL, this is just me spending some of my
spare time doing a fun coding project so if your machine sprouts legs
and refuses to work until it receives part of the TARP bailout it's
not my fault.

Here's the link:

http://www.snort.org/users/roesch/code/iplist.patch.tgz


Technorati Tags:
, , , ,


Labels: , , , , ,

Sunday, April 19, 2009

RSA 2009

I'll be out at RSA in San Francisco all this week. I'm speaking at the America's Growth Capital conference tomorrow at 2:30 on "Snort and The Future of Real-Time Adaptive Network Security". Wednesday I'll be doing a Peer2Peer talk at RSA on "The Future of Snort", primarily focusing on Snort 3.0 and upcoming changes to snort.org.

For those of you attending RSA I hope to meet you out there!

Labels: ,

Thursday, April 02, 2009

Snort 3.0 Beta 3 Released


It's been quite a while since the last Snort 3.0 beta and yesterday we released Beta 3. The reason that it's taken so long to get out the door is that we decided to start doing performance analysis of the Snort 2.8.x analytic engine that was ported over to run on top of SnortSP and the results were... interesting.

When I started developing and designing the Snort 3.0 architecture one of the assumptions that I based my design around was that multi-core computing environments were going to be the norm rather than the exception in the platforms we'd target moving forward. With that in mind and knowing the typical packet analysis load we place on machines with Sourcefire's applications I was looking to utilize CPU cycles more efficiently by performing common processing that happened for every packet (acquire/decode/flow/stream/etc) once and then spreading the analysis (Snort/RNA/etc) across the cores in separate threads. This would allow us to perform parallel processing across analytic engines while only having to perform the common processing tasks they all have to do once.

Snort_3_Arch_Threaded.png

This is great in theory and seemed like we'd see some real performance gains but when we started looking at the Snort 2.8.3.x analytic engine that we put out in the original Beta release we saw that performance was not where we wanted it to be relative to the monolithic Snort 2.8.3.x architecture. Initially we thought that the performance discrepancies were due to inefficiencies that were a byproduct of porting the monolithic Snort 2 packet processing engine to run in a threaded environment due to the incorporation of things like thread-local storage (TLS). Lots and lots of analysis was done over several months, tons of optimizations were made by Russ Combs and Ron Dempster, Snort's run-time processing cycle was studied at length and at the end of the day the performance still wasn't where we wanted it.

Eventually we arrived at the conclusion that the performance issues we were seeing were stemming from the way that modern Intel CPUs use and synchronize cache memory. If you'd like to see some more in-depth discussion on the Intel CPU caching architecture you should take a look at Gustavo's site and check out the articles on caching. The performance hangup we ran into really manifested itself as we tried to distribute traffic across cores on multiple physical dies, the overhead incurred by the data transfers and cache coherency operations required by the cores was costing us lots of CPU cycles.

What has become apparent from performing our analysis and extensive experimentation is that data spreading across the current generation of multi-core Intel CPUs is not something that works well for real-time applications like IPS. Intel CPUs really seem to favor the more traditional load balancing approach that's been used successfully with the Snort 2.x code base for years where independent processes are locked to separate cores and flows are unique to each respective process.

While we were exploring the performance envelope of the Snort 3 code base we looked at a number of different data distribution architectures to move data from the data source subsystem of SnortSP to the analytic engines (i.e. the Snort 2.8.3 engine module). A model that we've found to work well is what we've come to call the "stacks model". The stacks model works a lot like the Snort 2.x preprocessor subsystem but on a somewhat larger scale. Instead of running several analytic engines in separate threads with each thread locked to a CPU, the stacked model runs the engines in the one thread and calls them sequentially, passing the packet stream from engine to engine. The stacks model is included in Beta 3 and is a compile-time option for running the system.

Snort_3_Arch_Stacked.png

One model that we haven't benchmarked extensively is what I'll call a "single core multithreaded model" where we run one thread per analytic engine but lock them all to the same CPU core, eliminating the cache coherency and sync overhead while paying the price of heavier loading on the individual CPU cores. This will be an area of further research down the road.

We are planning on standing up a public CVS server in the near future to host the Snort 3 code so that we can foster better interaction with the open source community.

The next big hurdles to get over with Snort 3 are development of the TCP stream management subsystem and the Snort 3.0 analytic engine module. Stay tuned for more (and more regular) releases as we get rolling on these subsystems.

Labels: , , ,

Sunday, August 10, 2008

Snort 3.0 Architecture Series Part 3: The command shell


One of the biggest user-facing changes in the Snort 3 architecture is the inclusion of a user shell interface to interact with the system. Up until now everything has been controlled strictly via the command line interface at startup time and via signals sent to the process. There are many reasons for going with a command shell that I detailed in the first part of this series but basically since Snort is designed to be able to run continuously now it was essential to have a way to interact with it.

Upon starting SnortSP you are sent directly to the command shell prompt.

[+] Loaded pcap DAQ
[+] Loaded file DAQ
[+] Loaded afpacket DAQ
[*] DAQ Modules Loaded...
[*] Loading decoder modules
[+] Loaded ethernet
[+] Loaded null
[+] Loaded arp
[+] Loaded ip
[+] Loaded tcp
[+] Loaded udp
[+] Loaded icmp
[+] Loaded icmp6
[+] Loaded gre
[+] Loaded mpls
[+] Loaded 8021q
[+] Loaded ipv6
[+] Loaded ppp
[+] Loaded pppoe
[+] Loaded gtp
[+] Loaded raw
[*] Decoder initialized...
[*] Flow manager initialized...
[*] Data source subsystem loaded
[*] Engine manager initialized
Control thread running - 3082939280 (18555)
[*] Loading command interface
[!] Loading SnortSP command metatable
[!] Loading data source command metatable
[!] Loading engine command metatable
[!] Loading output command metatable
[!] Loading analyzer command metatable
Executing etc/snort.lua
,,_ -*> SnortSP! <*-
o" )~ Version 3.0.0b2 (Build 9) [BETA]
'''' By Martin Roesch & The Snort Team: http://www.snort.org/team.html
(C) Copyright 2008 Sourcefire Inc.
snort>


If this is your first time running Snort you'll probably want to get help. Every subsystem in the Snort 3 architecture has its own help function available as do the engine modules, if you ever get lost working with a module just invoke its object help function. For example:

snort> ssp.help()
[*] SnortSP Commands:
help()
set_log_level( [debug|info|notice|warn|error|critical] )
shutdown()
Available subsystems within SnortSP have their own help() methods:
dsrc - Data Source
eng - Dispatcher/Engine
analyzer - Analytics Modules
output - Output Modules
For example: dsrc.help() will call the Data Source help function


As you can see, the top level module for SnortSP is called "ssp" and you can invoke its help function by calling it with a "ssp.help()" function. If you want to find out the data source subsystem's available functions simply call "dsrc.help()" and so on.

One cool thing: if your system has Readline support available the Lua interpreter will pick it up automatically and you'll have standard shell functionality available within SnortSP such as command history and command line editing.

Under the covers a few things are happening. When a command is invoked in SnortSP there are a series of lookups performed by the code in the src/platform/lua_interface.c file. Lua is really handy for wrapping C function calls, it's one of the initial reasons I went with it for Snort. Let's take a look at some of the simple functionality in the lua_interface.c file for the ssp.* commands.


static int set_log_level_wrap(lua_State *L) {
int level;

if (lua_isnumber(L, 1))
{
level = lua_tointeger(L, 1);
}
else
{
const char *name = (char *) luaL_checkstring(L, 1);
if (name ==NULL) return 0;

if (strcasecmp(name, "debug") == 0) level = S_LOG_DEBUG;
else if (strcasecmp(name, "info") == 0) level = S_LOG_INFO;
else if (strcasecmp(name, "notice") == 0) level = S_LOG_NOTICE;
else if (strcasecmp(name, "warn") == 0) level = S_LOG_WARN;
else if (strcasecmp(name, "error") == 0) level = S_LOG_ERROR;
else if (strcasecmp(name, "critical") == 0) level = S_LOG_CRITICAL;
else return 0;
}
log_set_current_log_level(level);
level = log_get_current_log_level();
S_INFO("Log level set to %s", log_level_to_string(level));
return 0;
}

static int shutdown_wrap(lua_State *L) {
stop_processing = 1;
return 0;
}

static int platform_help_wrap(lua_State *L) {
printf("[*] "PLATFORM_NAME" Commands:\n"
" help()\n"
" set_log_level( [debug|info|notice|warn|error|critical] )\n"
" shutdown()\n"
" Available subsystems within "PLATFORM_NAME" have their own help() methods:\n"
" dsrc - Data Source\n"
" eng - Dispatcher/Engine\n"
" analyzer - Analytics Modules\n"
" output - Output Modules\n"
" For example: dsrc.help() will call the Data Source help function\n");
return 0;
}

static void platform_set_info(lua_State *L) {
lua_pushliteral (L, "_COPYRIGHT");
lua_pushliteral (L, "Copyright (C) 2008 Sourcefire Inc.");
lua_settable (L, -3);
lua_pushliteral (L, "_DESCRIPTION");
lua_pushliteral (L, "Network Intrusion Prevention System command interface");
lua_settable (L, -3);
lua_pushliteral (L, "_VERSION");
lua_pushliteral (L, PLATFORM_NAME" 0.1");
lua_settable (L, -3);
}

static const struct luaL_reg platformlib[] = {
{"help", platform_help_wrap},
{"shutdown", shutdown_wrap},
{"set_log_level", set_log_level_wrap},
{NULL, NULL},
};

static int platform_dir_create_meta (lua_State *L) {
luaL_newmetatable (L, METATABLE);
/* set its __gc field */
lua_pushstring (L, "__gc");
lua_settable (L, -2);
return 1;
}

static int luaopen_platform(lua_State *L) {
platform_dir_create_meta(L);
S_INFO("[!] Loading "PLATFORM_NAME" command metatable");
luaL_openlib(L, PLATFORM_PROMPT, platformlib, 0);
platform_set_info(L);
return 1;
}


This code sets up a "metatable" in Lua which allows us to call functions from its root with dot notation. The call to bind the root name is a little hidden in this case, it's the luaL_openlib() call in the last function above. We ended up using the PLATFORM_PROMPT substitution due to our habit of renaming the whole project periodically in its earlier days....

The array definition at the top of the code listing shows how the keywords are being mapped to the function calls themselves. When you put it all together, if you call "PLATFORM_PROMPT.help()" it maps that back to calling the platform_help_wrap() function. If you're familiar with the internals of Snort 1.x-2x you'll know that this mapping of keywords in the interpreter to function calls is very similar to how Snort's parser worked so it was a very comfortable transition for me. Add in the validation and scripting that you can get from lua and you can do some really cool stuff!

Let's take a look at a sample lua function scripting the SnortSP architecture to demonstrate the power of this arrangement. One of the things I wanted to do with SnortSP in its early days is test out the decoders to make sure there were no huge flaws in any of them that would lead to crash, as you know Snort's decoders are "critical infrastructure" that must be fast and crash free, the rest of the system is counting on them. The function I wrote would allow a user to point Snort at a directory of pcap files and process each one sequentially until every file in the directory had been processed.

In the old days we would have had to start a new instance of Snort (2.x) for each file we wanted to process and take all the time to load and shutdown. In SnortSP you could (in theory) load a detection configuration and then process each file, all without having to restart. The way the function is setup right now it just processes the file and prints the packet dump to the screen. Here's a listing.

require"lfs"     # load filesystem functions

function rundir (path, mask) # args are path to pcap files, filename mask
once = 0 # initialize the data source once only
for file in lfs.dir(path) do # grab the path
if string.match(file, mask) ~= nil then # find files that match the mask
print("Processing File "..path..'/'..file)
if(once == 0) then # setup the dsrc params once only
once = 1
dsrc1 = {name="src1",
type="pcap",
intf="file",
filename=path..'/'..file,
flags=1,
snaplen=0,
maxflows=16384,
maxidle=10,
flow_memcap=10000000,
display="max"}
dsrc.new(dsrc1) # instantiate the dsrc once only
eng.new("e1") # instantiate the dispatcher once only
eng.link({engine="e1", source="src1"}) # link dsrc to dispatcher
print("Starting engine")
eng.start("e1") # run it
else
eng.run_file("e1", path..'/'..file) # just fun the file now
end
end
end
if(once == 1) then # process the last file too
eng.run_file("e1", "")
end
end


The first thing happening here is the inclusion of a Lua library called "lfs". That's necessary for the filesystem interface, Lua doesn't ship with one natively. (I know.) After that it's the function definition which takes two arguments, the path to the directory containing the pcap files and the filename mask to use to select the right files from the directory. The first iteration through the config data structures and engine objects are instantiated and configured and the first file is processed, after that it just processes all the rest of the files in the directory.

This is pretty cool! Practically speaking you can script the startup and shutdown of Snort and script the operation of all the different system objects as well. For example, you can make external system calls to lookup runtime parameters like interface configuration or available memory and use that information to tune your runtime configuration parameters of your engine. You can also script testing new software modules or even get into more crazy stuff like automatically turning engine modules on and off at certain times of day or pretty much anything else you can imagine.

This is just a brief tour of the functionality of the command line, there's more that can be done! I'll leave it to interested readers to explore the SnortSP command shell and I'd love to hear about interesting things you do with it.

In the next part of the series I'll start writing about the data source subsystem and its components.

Labels: , , , ,

Thursday, August 07, 2008

Snort 3.0 Architecture Series Part 2: Changes and Betas

Things have changed a bit in the Snort 3.0 world since my last post so I thought I'd provide an update as a foundation for moving forward with this "series". I promise it'll be more than one article!

In Part 1 I discussed the architecture of the Snort 3.0 technology and since then there have been some changes. The largest change has been organizational in nature. We've decided to name the core system framework apart from the overall project since you can do more than just Snort-style intrusion detection with it. So, as a result from now on we'll be calling the software framework SnortSP (the Snort Security Platform) and then the engines will be named separately. The overall architectural umbrella that this all lives under is still going to be called the "Snort 3 Architecture" and it will consist of different software components, chief among them will be SnortSP and the engine modules that utilize it.

Here's a handy reference diagram:

SnortSP engine block diagram.jpg


Ok, now that that's out of the way, let's talk about the beta. On June 30th we released the initial beta of SnortSP & the Snort 2.8.2 Engine to open source beta. It's located at http://www.snort.org/dl/snortsp. To date we have done three releases of the code base with progressive versions nailing down loose ends and fixing compilation issues and the like.

We would love any feedback that people have on the betas, if you're a Snort fan you should definitely check it out and start getting your feet wet, this is the future of Snort!

For my next post I'll be spending some time talking about the SnortSP command shell and some neat stuff you can do with it!




Technorati Tags:
, , , ,


Labels: , , , ,

Thursday, November 08, 2007

Snort 3.0 Architecture Series Part 1: Overview

Snort 3.0 is the next generation Snort engine that is currently under active development at Sourcefire. I have been acting as lead architect as well as a contributing developer on the project for many months now. As one of the people who's driving development of the system I thought it would be worthwhile to start talking about what we're building because I know a lot of people are interested in learning more about this next generation Snort engine.

Snort is 9 years old this month and has a lot of miles under its belt. It's one of the most widely deployed network security technologies in the world and is therefore one of the most highly exposed (in terms of live network packets processed) and well tested IDP code bases available today. Snort 3.0 is a huge undertaking but I feel its a worthwhile effort to achieve some of the long term goals that we have for the engine. I believe that ultimately our users will benefit tremendously from the design of the new engine and that it will be a platform that will work well for the at least the next 9 years.

There are several goals associated with Snort 3.0's development:

0) Rewrite the core frameworks for Snort from the ground up to clean out code base cruft and leverage external libraries where possible to contain the scope of the rewrite. This will also allow us to flush unused features and effectively reduce the size and complexity of the code base making it easier to extend and ultimately lending the security benefits of a smaller code base.

1) Build an "contextually aware engine", one that has the ability to understand what it's defending built around the concept of network context. Network context is essentially data about the environment that is being defended by Snort, the composition of the hosts in the network as well as the local network composition. This is important in Snort 3 in order to:
  • Reduce/simplify/eliminate tuning as much as possible leveraging network context.

  • Generate event priorities based on network context.

  • Address network and transport layer evasion by leveraging network context.

2) Abstract and compartmentalize Snort's subsystems to make components "separable".
  • Compartmentalize common functionality that any network traffic analysis application would need to enable Snort to be a more effective platform for building arbitrary network traffic analyzers.

3) Improve support for protocol encapsulation within the overall engine architecture to make handling things like enterprise/WAN protocols and IPv6 support more natural.

4) Add an interactive shell to the system so that it may be more fully orchestrated at runtime.

5) Multithread the engine to take better advantage of multi-core platforms that are standard today.
  • Make the engine parallalizable so that multiple analytics threads may run simultaneously on the same traffic.

6) Normalize Snort's language so that it's easier to read and write.

Snort3BlockDiagram.png


As a result of these goals the engine architecture has a number of major discrete software components.

1) Data Source. The Data Source component encapsulates common functionality required by any network traffic analyzer, functions that will have to be performed prior to running almost any analysis task. The data source incorporates a number of components including:
  • Data Acquisition (DAQ) - The DAQ provides an interface between the rest of the engine and the host OS packet facilities. This is where we get packets from the underlying hardware and where we talk to that hardware regarding the disposition of those packets. The DAQ subsystem allows Snort 3.0 to incorporate arbitrary external packet interfaces including things like libpcap, IPQ and divert sockets.

  • Decoder - The Decoder performs basically the same tasks it did in Snort 2.x. Validate the packets, detect protocol anomalies and provide a referential structure for the rest of the program to operate upon.

  • Flow Manager - The Flow Manager provides services for tracking conversations between endpoints on the network. In Snort 3.0 it also contains features for "fastpathing" traffic, allowing it to pass straight through the engine in the event that the analytics modules have decided that they're not interested in a particular flow any longer. Snort 3.0 also includes a mechanism called "flow slots" that subsystems can use to store stateful "flow local" information. This is the place that things like flowbits will get stored in Snort 3.0.

  • IP Defragmenter - This module provides services for putting IPv4 and IPv6 packets back together and will include mechanisms to allow for target-based fragment reassembly.

  • TCP Stream Reassembler - As with the IP Defragmenter, provides target-based services for reassembling TCP segments into normalized streams and presenting them to the underlying analytics.

  • Data Source API - An abstraction API between the facilities provided by the data source and the rest of the Snort 3.0 software framework. This API exists to that the rest of Snort 3.0 can work without caring whether the Data Source is implemented as hardware or software.

2) Action System. The Action System handles event queuing, notification and logging when the system fires events. The supported output types in Snort 3.0 will be text (console), syslog and Unified 2, a serialized binary stream format.

3) Attribute Management System (AMS). The AMS will store network contextual data about the operational environment being defended by a particular Snort instance. This subsystem will be addressable continuously at runtime and provide interactive interfaces to the command shell as well as analytics modules that can leverage its data. The inclusion of the AMS will make all the goals in section 1 of the goals section attainable.

4) Analytics System. The Analytics System is where Snort detection engine threads will be located. The idea in Snort 3.0 is to put all detection logic in analytics modules that run as separate threads, all the other code exists to support the functions of the Analytics System. Multiple threads may operate on the data coming from a dispatcher instance simultaneously. The Analytics System is structured so that all interaction between the analytics modules and the rest of the Snort 3.0 framework is brokered by an API called the "Snort Abstraction Layer" (SAL). Note that arbitrary functions may be performed by analytics modules in a given runtime instance. For example the Sourcefire edition of this engine is going to include RNA's functionality as an analytics module running side-by-side with Snort 3.0.

5) Dispatcher. The Dispatcher exists to coordinate information flow between the different components of Snort 3.0 and to manage traffic queuing and disposition across analytics threads. It also ties together all of the objects in a runtime instance of a Snort engine, uniting data source, analytics, action system and the attribute manager into a single manageable entity for the purposes of process and threat management from the command shell.

6) Snortd and the command shell. Snortd is the daemon process that provides marshaling services for the objects that are instantiated in a particular framework instance. The command shell also runs attached within a thread to snortd. The command shell provides interactive object management services for different software modules, runtime management of the process and threads, health management and a full scripting language for Snort 3.0. The command shell is running the Lua scripting language, a lightweight embeddable scripting language that is fast and portable as well as being very nice for implementing Domain Specific Languages. If Snort's parser wasn't one of your favorite features in the past you should definitely like this change! For those of you wondering if Snort 3.0 will handle Snort's existing rules language, of course it will. We're not planning on throwing out 9 years of accumulated detection functionality!

The analytics modules that are under development right now (that I can discuss) include a Snort 2.x detection engine implementation, RNA (for Sourcefire implementations) and a Lua traffic analysis module for users who are in environments where a scripting interface to traffic analysis would be very useful.

Over the coming days and weeks I am planning to post a subsystem by subsystem design overview of the engine components so that users of the system may familiarize themselves with the system as we prepare to release additional alpha code snapshots on our way to a Snort 3.0 beta!



Technorati Tags:
, , , ,


Labels: , , ,