Sunteți pe pagina 1din 22

SnortTM diagrams for developers

by:

Andrés Felipe Arboleda


aarboleda@unicauca.edu.co

Charles Edward Bedón


cbedon@unicauca.edu.co

Universidad del Cauca - Colombia

14th – April – 2005

Version 0.2 alpha


Copyright © 2005 Andrés Felipe Arboleda, Charles Edward Bedón
Contents

Introduction
1. General operation
Sequence diagrams 1, 2 and 3 – Snort initialization and rules file parsing
2. Rules file parsing
Function ParseRulesFile()
Function ParseRule()
Function ProcessHeadNode()
Function ParseRuleOptions()
3. Data structures after parsing
Sequence diagram 4 – Fast packet detection engine initialization
4. Initialization of the fast packet detection engine
Sequence diagrams 5 and 6 – When a packet arrives
5. Tools and resources
6. Source code statistics
7. To do
References
INTRODUCTION

Diagrams shown on next pages aim to represent a part of Snort functionality. Objects from UML sequence
diagrams (rectangles on top of each diagram) represent source code files, and messages (arrows) represent calls to
functions within such files.

All sequence diagrams are sorted by execution, in other words, Snort execution begins with the diagram shown in
Figure 1 continuing with diagram in Figure 2 and so on.

This document does not describe in a detailed way Snort source code, it is just kinda map for people who want to
know on which part of the code is located when is reading one of the Snort’s source files.

This diagrams were done for Snort-2.2.0, executed with the next command line:

snort -d -l <path to log directory> -c <path to configuration file>

This document is a sub-product of the degree work named “Intrusion Detection System Using Artificial
Intelligence”, that is being developed by the authors under direction of Engineer Siler Amador Donado. Comments
and suggestions are welcome.
1. GENERAL OPERATION

Figure 1. Snort block diagram.

Each module is described as follows

Decoder: fits the captured packets into data structures and identifies link level protocols. Then, it takes the next
level, decodes IP, and then TCP or UDP depending on the case in order to get useful information like ports and
addresses. Snort will alert if it finds malformed headers, unusual length TCP options and things like that.
Preprocessors: They could be seen like some kind of filter, which identifies things that should be checked later (in
the next modules e.g. the Detection Engine), such as suspicious connection attempts to some TCP/UDP ports or too
many UDP packets sent in a short period of time (port scan). Preprocessors function is to take packets potentially
dangerous for the detection engine to try to find known patterns.

Rules Files: These are plane text files which contain a list of rules with a known syntax. This syntax includes
protocols, addresses, output plug-ins associated and some other things. Those rules files are updated like the virus
definition files are.

Detection Plug-ins: Those modules are referenced from its definition in the rules files, and they're intended to
identify patterns whenever a rule is evaluated.

Detection Engine: Making use of the detection plug-ins, it matches packets against rules previously charged into
memory since Snort initialization.

Output Plug-ins: These modules allow to format the notifications (alerts, logs) for the user to access them by many
ways (console, extern files, databases, etc).
Figure 2. Snort initialization (Sequence diagram 1).
Figure 3. Snort initialization (Sequence diagram 2).
Figure 4. Rules file parsing (Sequence diagram 3).
2. RULES FILE PARSING

Next functions are within the file ./parser.c.

· Function ParseRulesFile()

This function analyses, through a cycle, each configuration file line (i.e.: snort.conf). If the line is a valid rule (is not
a commentary), it is passed to the rule parser (the function ParseRule()).

· Function ParseRule()

This function is executed one time per each valid rule in the configuration file. Initially, it searches for lines that are
not detection rules, in other words, instructions like include, var, preprocessor, output plugins, config, etc. In case
of finding preprocessors and output plugins, it calls the initialization functions for each one.

If the rule is a detection one, it is to say, begins with alert, log, pass, activation or dynamic, the rule is verified and
charged into memory by the function ProcessHeadNode().

The detection rules are stored in memory inside the structures RuleTreeNode (RTN) and OptTreeNode (OTN);
such structures are declared in the file ./rules.h.

A detailed explanation can be found in question “3.17 How does rule ordering work?” of [SnortFAQ 03].

· Function ProcessHeadNode()

This is the function’s prototype:

ProcessHeadNode(RuleTreeNode *test_node, ListHead *list, protocol)

It takes a RTN pointed by test_node and attaches it at the end of the RTNs chain of the respective protocol, in the
ListHead pointed by list [Schildt 90].
Figure 5. Data structures associated to ProcessHeadNode().

· Function ParseRuleOptions()

This is the function’s prototype:

ParseRuleOptions(char *rule, int rule_type, int protocol)

It creates OTNs and attaches them to the RTN pointed by the global variable rtn_tmp which is set by the function
ProcessHeadNode(). This last was called previously by ParseRule().

In this manner gets formed the RTNs and OTNs linked matrix (we call linked matrix to a two dimensional linked list
structure) which is the place where rules are stored in memory. RTNs keep data previously given by the rule header,
while OTNs keep data given by the rule options section.

An example rule:

alert tcp any any -> 192.168.1.0/24 111 (content:”|00 01 86 a5|”; msg:”mountd access”;)
|------------------- Header ------------------|---------------------- Options ------------------------|
The linked matrix is shown as follows. In the figure each square represents a data structure and each arrow, a
pointer.

Figure 6. Linked matrix.

3. DATA STRUCTURES AFTER PARSING

After the rules file is parsed, these rules keep stored in RTNs and OTNs forming the next structure.
Figure 7. Where rules are stored.

RuleLists pointer is a global variable declared in the file ./parser.c, it is useful to go over all rules that are stored in
memory. It points to the first element of a RuleListNode linked list. Each node of the list has a ListHead pointer,
there is one for each rule type (Alert, Dynamic, Log, Pass and Activation). Finally, each ListHead has four pointers,
one per protocol (Ip, Tcp, Udp and Icmp); each pointer points to a RTNs and OTNs linked matrixes where rules are.
In other words, it could be up to four matrixes per rule type.
Figure 8. Fast packet detection engine initialization (Sequence diagram 4).
4. INITIALIZATION OF THE FAST PACKET DETECTION ENGINE

Initialization begins with the calling to function fpCreateFastPacketDetection() in the file ./fpcreate.c from
SnortMain(). Function fpCreateFastPacketDetection() goes over all rules stored in memory using the global
variable RuleLists which is a RuleListNode pointer, each rule is classified according to its content (Content,
UriContent o NoContent). Content is determined through the OTN associated with the rule. In this OTN exists a
field named ds_list, it is an array of pointers pointing to diverse data structures, depending on type of these
structures the content is set.

After that first classification, it is determined if the rule is bidirectional and either the function prmAddRule(),
prmAddRuleUri() or prmAddRuleNC() is called depending on content type. These functions sort rules in tables
according to source-port and destination-port given in the rule. The objective of all this is to make the packet
comparison to rules faster as possible.
Figure 9. Data structures associated to fast packet detection engine.

If we look into the function fpCreateFastPacketDetection(), we found declared one PORT_RULE_MAP for each
protocol (tcp, udp, ip, icmp), inside each PORT_RULE_MAP there are three groups of PORT_GROUP: one is the
source port table (prmSrcPort), other is the destination port table (prmDstPort) and last is the generic table
(prmGeneric) which is used for rules with srcport=any and dstport=any.
Figure 10. When a packet arrives (Sequence diagram 5).
Figure 11. When a packet arrives (Sequence diagram 6).
5. TOOLS AND RESOURCES

· OpenOffice 1.1.4
· O.S.: Linux (Mandrake 10.1 Official).
· IDE: Kdevelop v3.0 (GNU tools: make, gdb, ...)
6. SOURCE CODE STATISTICS

For Snort-2.2.0.

· General

Number of .c files 135


Number of .h files 154
Number of source code lines (approx.) 99.317
Total size of files 2’471.751 bytes

Number of .c and .h files per directory:

Directory Number of Number of Number of Number of Total code lines


.c files .h files code lines code lines in .c and .h files
in .c files in .h files
./ 27 41 26.794 5.821 32.615
./detection-plugins 28 28 10.417 756 11.173
./output-plugins 11 11 7.417 362 7.779
./parser 1 1 312 48 360
./preprocessors 18 19 17.724 951 18.675
./preprocessors/flow 13 16 4.498 835 5.333
./preprocessors/HttpInspect 14 19 5.885 923 6.808
./sfutil 17 18 12.587 1.974 14.561
./win32/WIN32-Code 6 1 1.887 126 2.013
TOTALS: 135 154 87.521 11.796 99.317

Number of source code lines includes commentaries in each file.


7. TO DO

· Explain each referenced file in the sequence diagrams and say more things about those diagrams

· Explain many other processes inside Snort like preprocessors, what happens once a packet arrives and a long list
of things.

· Update this documentation for 2.3+ versions of Snort

· Release the documentation in other formats (e.g. HTML)


REFERENCES

[Schildt 90] Herbert Schildt. “C: Manual de referencia”. Segunda edición, Ed. McGraw-Hill, España 1990.

[SnortFAQ 03] The Snort Core Team. “The Snort FAQ”, http://www.snort.org. 2005.

S-ar putea să vă placă și