Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

sp_clientserver.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /* sp_clientserver 
00004  * 
00005  * Purpose:
00006  *
00007  * Wouldn't be nice if we could tell a TCP rule to only apply if it's going 
00008  * to or from the client or server side of a connection?  Think of all the 
00009  * false alarms we could elminate!  That's what we're doing with this one,
00010  * it allows you to write rules that only apply to client or server packets.
00011  * One thing though, you *must* have stream4 enabled for it to work!
00012  *
00013  * Arguments:
00014  *   
00015  *   None.
00016  *
00017  * Effect:
00018  *
00019  * Test the packet to see if it's coming from the client or the server side
00020  * of a connection.
00021  *
00022  * Comments:
00023  *
00024  * None.
00025  *
00026  */
00027 
00028 /* put the name of your pluging header file here */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include "config.h"
00032 #endif
00033 
00034 #include <sys/types.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <ctype.h>
00038 
00039 #include "rules.h"
00040 #include "decode.h"
00041 #include "plugbase.h"
00042 #include "parser.h"
00043 #include "debug.h"
00044 #include "util.h"
00045 #include "plugin_enum.h"
00046 #include "snort.h"
00047 
00048 
00049 
00050 typedef struct _ClientServerData
00051 {
00052     u_int8_t from_server;
00053     u_int8_t from_client;    
00054     u_int8_t ignore_reassembled; /* ignore reassembled sessions */
00055     u_int8_t only_reassembled; /* ignore reassembled sessions */
00056 } ClientServerData;
00057 
00058 void FlowInit(char *, OptTreeNode *, int);
00059 void ParseFlowArgs(char *, OptTreeNode *);
00060 void InitFlowData(OptTreeNode *);
00061 int CheckFromClient(Packet *, struct _OptTreeNode *, OptFpList *);
00062 int CheckFromServer(Packet *, struct _OptTreeNode *, OptFpList *);
00063 int CheckForReassembled(Packet *, struct _OptTreeNode *, OptFpList *);
00064 int CheckForNonReassembled(Packet *p, struct _OptTreeNode *, OptFpList *);
00065 
00066 
00067 /****************************************************************************
00068  * 
00069  * Function: SetupClientServer()
00070  *
00071  * Purpose: Generic detection engine plugin template.  Registers the
00072  *          configuration function and links it to a rule keyword.  This is
00073  *          the function that gets called from InitPlugins in plugbase.c.
00074  *
00075  * Arguments: None.
00076  *
00077  * Returns: void function
00078  *
00079  ****************************************************************************/
00080 void SetupClientServer(void)
00081 {
00082     /* map the keyword to an initialization/processing function */
00083     RegisterPlugin("flow", FlowInit);
00084 
00085     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00086                             "Plugin: ClientServerName(Flow) Setup\n"););
00087 }
00088 
00089 
00090 /****************************************************************************
00091  * 
00092  * Function: FlowInit(char *, OptTreeNode *)
00093  *
00094  * Purpose: Configure the flow init option to register the appropriate checks
00095  *
00096  * Arguments: data => rule arguments/data
00097  *            otn => pointer to the current rule option list node
00098  *
00099  * Returns: void function
00100  *
00101  ****************************************************************************/
00102 void FlowInit(char *data, OptTreeNode *otn, int protocol)
00103 {
00104     if(protocol != IPPROTO_TCP)
00105     {
00106         FatalError("%s(%d): Cannot check flow connection "
00107                    "for non-TCP traffic\n", file_name, file_line);
00108     }
00109 
00110     /* multiple declaration check */
00111     if(otn->ds_list[PLUGIN_CLIENTSERVER])
00112     {
00113         FatalError("%s(%d): Multiple flow options in rule\n", file_name, 
00114                 file_line);
00115     }
00116         
00117 
00118     InitFlowData(otn);
00119     ParseFlowArgs(data, otn);
00120 }
00121 
00122 
00123 
00124 /****************************************************************************
00125  * 
00126  * Function: ParseFlowArgs(char *, OptTreeNode *)
00127  *
00128  * Purpose: parse the arguments to the flow plugin and alter the otn
00129  *          accordingly
00130  *
00131  * Arguments: otn => pointer to the current rule option list node
00132  *
00133  * Returns: void function
00134  *
00135  ****************************************************************************/
00136 void ParseFlowArgs(char *data, OptTreeNode *otn)
00137 {
00138     char *token, *str, *p;
00139     ClientServerData *csd;
00140 
00141     csd = (ClientServerData *)otn->ds_list[PLUGIN_CLIENTSERVER];
00142 
00143     str = strdup(data);
00144 
00145     if(str == NULL)
00146     {
00147         FatalError("ParseFlowArgs: Can't strdup data\n");
00148     }
00149 
00150     p = str;
00151 
00152     /* nuke leading whitespace */
00153     while(isspace((int)*p)) p++;
00154 
00155     token = strtok(p, ",");
00156 
00157     while(token) 
00158     {
00159         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00160                     "parsed %s,(%d)\n", token,strlen(token)););
00161 
00162         while(isspace((int)*token))
00163             token++;
00164 
00165         if(!strcasecmp(token, "to_server"))
00166         {
00167             csd->from_client = 1;
00168         }
00169         else if(!strcasecmp(token, "to_client"))
00170         {
00171             csd->from_server = 1;
00172         } 
00173         else if(!strcasecmp(token, "from_server"))
00174         {
00175             csd->from_server = 1;
00176         } 
00177         else if(!strcasecmp(token, "from_client"))
00178         {
00179             csd->from_client = 1;
00180         }
00181         else if(!strcasecmp(token, "stateless"))
00182         {
00183             otn->stateless = 1;
00184         }
00185         else if(!strcasecmp(token, "established"))
00186         {
00187             otn->established = 1;
00188         }
00189         else if(!strcasecmp(token, "not_established"))
00190         {
00191             otn->unestablished = 1;
00192         }
00193         else if(!strcasecmp(token, "no_stream"))
00194         {
00195             csd->ignore_reassembled = 1;
00196         }
00197         else if(!strcasecmp(token, "only_stream"))
00198         {
00199             csd->only_reassembled = 1;
00200         }
00201         else
00202         {
00203             FatalError("%s:%d: Unknown Flow Option: '%s'\n",
00204                        file_name,file_line,token);
00205 
00206         }
00207 
00208 
00209         token = strtok(NULL, ",");
00210     }
00211 
00212     if(csd->from_client && csd->from_server)
00213     {
00214         FatalError("%s:%d: Can't use both from_client"
00215                    "and flow_from server", file_name, file_line);
00216     }
00217 
00218     if(csd->ignore_reassembled && csd->only_reassembled)
00219     {
00220         FatalError("%s:%d: Can't use no_stream and"
00221                    " only_stream", file_name,file_line);
00222     }
00223 
00224     if(otn->stateless && (csd->from_client || csd->from_server)) 
00225     {
00226         FatalError("%s:%d: Can't use flow: stateless option with"
00227                    " other options", file_name, file_line);
00228     }
00229 
00230     if(otn->stateless && otn->established)
00231     {
00232         FatalError("%s:%d: Can't specify established and stateless "
00233                    "options in same rule\n", file_name, file_line);
00234     }
00235 
00236     if(otn->stateless && otn->unestablished)
00237     {
00238         FatalError("%s:%d: Can't specify unestablished and stateless "
00239                    "options in same rule\n", file_name, file_line);
00240     }
00241 
00242     if(otn->established && otn->unestablished)
00243     {
00244         FatalError("%s:%d: Can't specify unestablished and established "
00245                    "options in same rule\n", file_name, file_line);
00246     }
00247 
00248     if(csd->from_client) 
00249     {
00250         AddOptFuncToList(CheckFromClient, otn);
00251     } 
00252 
00253     if(csd->from_server) 
00254     {
00255         AddOptFuncToList(CheckFromServer, otn);
00256     }
00257 
00258     if(csd->ignore_reassembled) 
00259     {
00260         AddOptFuncToList(CheckForNonReassembled, otn);
00261     }
00262 
00263     if(csd->only_reassembled) 
00264     {
00265         AddOptFuncToList(CheckForReassembled, otn);
00266     }
00267 
00268     
00269     free(str);
00270 }
00271 
00272 /****************************************************************************
00273  * 
00274  * Function: InitFlowData(OptTreeNode *)
00275  *
00276  * Purpose: calloc the clientserver data node
00277  *
00278  * Arguments: otn => pointer to the current rule option list node
00279  *
00280  * Returns: void function
00281  *
00282  ****************************************************************************/
00283 void InitFlowData(OptTreeNode * otn)
00284 {
00285 
00286     /* allocate the data structure and attach it to the
00287        rule's data struct list */
00288     otn->ds_list[PLUGIN_CLIENTSERVER] = (ClientServerData *) 
00289         calloc(sizeof(ClientServerData), sizeof(char));
00290 
00291     if(otn->ds_list[PLUGIN_CLIENTSERVER] == NULL) 
00292     {
00293         FatalError("FlowData calloc Failed!\n");
00294     }
00295 }
00296 
00297 /****************************************************************************
00298  * 
00299  * Function: CheckFromClient(Packet *, struct _OptTreeNode *, OptFpList *)
00300  *
00301  * Purpose: Check to see if this packet came from the client side of the 
00302  *          connection.
00303  *
00304  * Arguments: data => argument data
00305  *            otn => pointer to the current rule's OTN
00306  *
00307  * Returns: 0 on failure
00308  *
00309  ****************************************************************************/
00310 int CheckFromClient(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00311 {
00312 #ifdef DEBUG_CS
00313     DebugMessage(DEBUG_STREAM, "CheckFromClient: entering\n");
00314     if(p->packet_flags & PKT_REBUILT_STREAM)
00315     {
00316         DebugMessage(DEBUG_STREAM, "=> rebuilt!\n");
00317     }
00318 #endif /* DEBUG_CS */    
00319 
00320     if(!pv.stateful)
00321     {
00322         /* if we're not in stateful mode we ignore this plugin */
00323         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00324     }
00325 
00326     if(p->packet_flags & PKT_FROM_CLIENT || 
00327             !(p->packet_flags & PKT_FROM_SERVER))
00328     {
00329         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00330     }
00331 
00332     /* if the test isn't successful, this function *must* return 0 */
00333     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "CheckFromClient: returning 0\n"););
00334     return 0;
00335 }
00336 
00337 
00338 /****************************************************************************
00339  * 
00340  * Function: CheckFromServer(Packet *, struct _OptTreeNode *, OptFpList *)
00341  *
00342  * Purpose: Check to see if this packet came from the client side of the 
00343  *          connection.
00344  *
00345  * Arguments: data => argument data
00346  *            otn => pointer to the current rule's OTN
00347  *
00348  * Returns: 0 on failure
00349  *
00350  ****************************************************************************/
00351 int CheckFromServer(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00352 {
00353     if(!pv.stateful)
00354     {
00355         /* if we're not in stateful mode we ignore this plugin */
00356         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00357     }
00358     
00359     if(p->packet_flags & PKT_FROM_SERVER || 
00360             !(p->packet_flags & PKT_FROM_CLIENT))
00361     {
00362         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00363     }
00364 
00365     /* if the test isn't successful, this function *must* return 0 */
00366     return 0;
00367 }
00368 
00369 
00370 /****************************************************************************
00371  * 
00372  * Function: int CheckForReassembled(Packet *p, struct _OptTreeNode *otn,
00373                                     OptFpList *fp_list)
00374  *
00375  * Purpose: Check to see if this packet came from a reassembled connection
00376  *          connection.
00377  *
00378  * Arguments: data => argument data
00379  *            otn => pointer to the current rule's OTN
00380  *
00381  * Returns: 0 on failure
00382  *
00383  ****************************************************************************/
00384 int CheckForReassembled(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00385 {
00386     /* is this a reassembled stream? */
00387     if(p->packet_flags & PKT_REBUILT_STREAM)
00388     {
00389         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00390     }
00391 
00392     /* if the test isn't successful, this function *must* return 0 */
00393     return 0;
00394 }
00395 
00396 
00397 /* 
00398  * Function: int CheckForNonReassembled(Packet *p, struct _OptTreeNode *otn,
00399                                     OptFpList *fp_list)
00400  *
00401  * Purpose: Check to see if this packet came from a reassembled connection
00402  *          connection.
00403  *
00404  * Arguments: data => argument data
00405  *            otn => pointer to the current rule's OTN
00406  *
00407  * Returns: 0 on failure
00408  *
00409  ****************************************************************************/
00410 int CheckForNonReassembled(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00411 {
00412     /* is this a reassembled stream? */
00413     if(p->packet_flags & PKT_REBUILT_STREAM)
00414     {
00415         return 0;
00416     }
00417 
00418     /* if the test isn't successful, this function *must* return 0 */
00419     return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00420 }

Generated on Sun May 14 14:51:13 2006 by  doxygen 1.4.2