Writing Plugins



A little about writing plugins

This is the section everyone wants (well since only 3 out of 60 people left the room when Marty started talking about in the Snort BOF, I will assume everyone wants it). Plugins are the easy way to making snort do more. They allow individuals to add complex detection capabilities to the detection engine, do odd things with incoming packets, and even stranger things with the alert output (anyone planning on writing an output plugin that drives the audio synth?). They can be written in any language that is capable of producing linkable object code (come on you Fortran junkies, lets see some plugins). And best of all, they are not complicated to write.

Since the different types of plugins are very similar in structure, I will explain the process of developing one by example. For this example we will follow the development of an output plugin. Specifically, we will incorporate the FastAlert commandline output format into a plugin. The format for this plugin (see the section about the rule file for more information on syntax) will be:

 output fastalert: /path/alertfile
 
There are six simple steps to writing a plugin. These are:

Setup the Source Files

OK, I will admit it, this is step is most likely unnecessary for all of you, but I am including it anyway. If you are going to write a plugin, you are going to need to create source files for the code. For most plugins, this will involve two files: a source file and a header file. There is a naming convention for these files based on the type of plugin that is being written. For preprocessors, the files begin with "spp_" and for detection plugins it is "sp_". Output plugins have an additional level of standardization. Alert level output plugins begin with "spo_alert_" and log level output plugins begin with "spo_log_". I must note that these are only conventions, not rules. However, following the conventions makes the code easier to understand. So for our example plugin, we will have two files: spo_alert_fast.h and spo_alert_fast.c. The contents of these two files (even though we have not written any code) is as shown below.

spo_alert_fast.h

#include "snort.h"

#ifndef __SPO_FASTALERT_H__
#define __SPO_FASTALERT_H__

/* list of function prototypes for this plugin */

#endif /* __SPO_FAST_ALERT_H__ */
This includes the snort header file, so we have access to other definitions, and it adds a set of defines to protect against recursive includes.

spo_alert_fast.c

/* plugin header file */
#include "spo_alert_fast.h"

/* external globals from rules.c */
extern char *file_name;
extern int file_line;

This includes the plugin header file and defines some global variables that are useful when reporting a syntax error from the parsing function. Additionally, these two files will often contain comments describing what the plugin does and copyright and licensing information.

Write the Setup Function

In order for a plugin to be used within snort, it must be registered. The registration process involves associating the plugin keyword with the plugin initialization function. The keyword is what is used in the rule file to reference the plugin. For the example plugin, we are using the keyword "fastalert". The code for the setup function (in spo_alert_fast.c) is:
void SetupFastAlert()
{
    /* link the preprocessor keyword to the init function in 
       the preproc list */
    RegisterOutputPlugin("fastalert", NT_OUTPUT_ALERT, FastAlertInit);

#ifdef DEBUG
    printf("Output plugin: FastAlert is setup...\n");
#endif
}
This function calls the function RegisterOutputPlugin with arguments for the keyword, the output type, and the name of the initialization function. There are currently two supported output types: alert and log. The definition for the alert output type is NT_OUTPUT_ALERT. For the log output type it is NT_OUTPUT_LOG. The functions for registering preprocessors and detection plugins are slightly different. They do not have the argument for the output type. Here are sample calls for registering a preprocessor and detection plugin, respectively.
	RegisterPreprocessor("keyword", PreprocessorInit);
	RegisterPlugin("keyword", DetectionPluginInit); 
In addition to the code in spo_alert_fast.c, we must add a function prototype to the file spo_alert_fast.h. This code would need to be inserted just after the "/* list of function prototypes ..." comment and it would look like this:
void SetupFastAlert();
It is important to remember that the keywords used for plugins must be unique. Once we have one plugin with the keyword fastalert we cannot have another one.

Write the Init Function


Write the Parsing Function


Write the Action Function


Adding the Setup Function Call to Plugbase



Plugin Initialization and Activation

There are two basic components to a plugin. There is the initialization and activation component and there is the functional component. The initialization and activation component is identical accross the three types of plugins. This component can be divided to two different subsections: plugin registration and plugin initialization.

Plugin Registration

In order for a plugin to be available for use from the rules file, it must be registered (or as Marty would put it it needs to be setup). This involves associating the plugin keyword with an initialization function. Here is a template for registering a plugin:
void SetupPlugin()
{
 	/* map the keyword to an initialization/processing function */
	RegisterPlugin("keyword", PluginInit);

#ifdef DEBUG
	printf("Plugin: PluginName Registered\n");
#endif
}
In order for this plugin to be available in snort, the setup function must be called.
Copyright 2000 Andrew R. Baker