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

sp_tcp_flag_check.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 /* $Id$ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include <sys/types.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 
00030 #include "rules.h"
00031 #include "decode.h"
00032 #include "plugbase.h"
00033 #include "parser.h"
00034 #include "debug.h"
00035 #include "util.h"
00036 #include "plugin_enum.h"
00037 
00038 #define M_NORMAL  0
00039 #define M_ALL     1
00040 #define M_ANY     2
00041 #define M_NOT     3
00042 
00043 typedef struct _TCPFlagCheckData
00044 {
00045     u_char mode;
00046     u_char tcp_flags; 
00047     u_char tcp_mask; /* Mask to take away from the flags check */
00048 
00049 } TCPFlagCheckData;
00050 
00051 void TCPFlagCheckInit(char *, OptTreeNode *, int);
00052 void ParseTCPFlags(char *, OptTreeNode *);
00053 int CheckTcpFlags(Packet *, struct _OptTreeNode *, OptFpList *);
00054 
00055 
00056 
00057 void SetupTCPFlagCheck(void)
00058 {
00059     RegisterPlugin("flags", TCPFlagCheckInit);
00060     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Plugin: TCPFlagCheck Initialized!\n"););
00061 }
00062 
00063 
00064 
00065 void TCPFlagCheckInit(char *data, OptTreeNode *otn, int protocol)
00066 {
00067     if(protocol != IPPROTO_TCP)
00068     {
00069         FatalError("Line %s (%d): TCP Options on non-TCP rule\n", file_name, file_line);
00070     }
00071 
00072     /* multiple declaration check */ 
00073     if(otn->ds_list[PLUGIN_TCP_FLAG_CHECK])
00074     {
00075         FatalError("%s(%d): Multiple TCP flags options in rule\n", file_name,
00076                 file_line);
00077     }
00078 
00079     otn->ds_list[PLUGIN_TCP_FLAG_CHECK] = (TCPFlagCheckData *)
00080             SnortAlloc(sizeof(TCPFlagCheckData));
00081 
00082     /* set up the pattern buffer */
00083     ParseTCPFlags(data, otn);
00084 
00085     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Adding TCP flag check function (%p) to list\n",
00086                             CheckTcpFlags););
00087 
00088     /* link the plugin function in to the current OTN */
00089     AddOptFuncToList(CheckTcpFlags, otn);
00090 
00091     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "OTN function CheckTcpFlags added to rule!\n"););
00092 }
00093 
00094 
00095 
00096 /****************************************************************************
00097  *
00098  * Function: ParseTCPflags(char *)
00099  *
00100  * Purpose: Figure out which TCP flags the current rule is interested in
00101  *
00102  * Arguments: rule => the rule string 
00103  *
00104  * Returns: void function
00105  *
00106  ***************************************************************************/
00107 void ParseTCPFlags(char *rule, OptTreeNode *otn)
00108 {
00109     char *fptr;
00110     char *fend;
00111     int comma_set = 0;
00112     TCPFlagCheckData *idx;
00113 
00114     idx = otn->ds_list[PLUGIN_TCP_FLAG_CHECK];
00115 
00116     fptr = rule;
00117 
00118     /* make sure there is atleast a split pointer */
00119     if(fptr == NULL) 
00120     {
00121         FatalError("[!] ERROR Line %s (%d): Flags missing in TCP flag rule\n", file_name, file_line);
00122     }
00123 
00124     while(isspace((u_char) *fptr))
00125         fptr++;
00126 
00127     if(strlen(fptr) == 0)
00128     {
00129         FatalError("[!] ERROR Line %s (%d): Flags missing in TCP flag rule\n", file_name, file_line);
00130     }
00131 
00132     /* find the end of the alert string */
00133     fend = fptr + strlen(fptr); 
00134 
00135     idx->mode = M_NORMAL; /* this is the default, unless overridden */
00136 
00137     while(fptr < fend && comma_set == 0)
00138     {
00139         switch(*fptr)
00140         {
00141             case 'f':
00142             case 'F':
00143                 idx->tcp_flags |= R_FIN;
00144                 break;
00145 
00146             case 's':
00147             case 'S':
00148                 idx->tcp_flags |= R_SYN;
00149                 break;
00150 
00151             case 'r':
00152             case 'R':
00153                 idx->tcp_flags |= R_RST;
00154                 break;
00155 
00156             case 'p':
00157             case 'P':
00158                 idx->tcp_flags |= R_PSH;
00159                 break;
00160 
00161             case 'a':
00162             case 'A':
00163                 idx->tcp_flags |= R_ACK;
00164                 break;
00165 
00166             case 'u':
00167             case 'U':
00168                 idx->tcp_flags |= R_URG;
00169                 break;
00170 
00171             case '0':
00172                 idx->tcp_flags = 0;
00173                 break;
00174 
00175             case '1': /* reserved bit flags */
00176                 idx->tcp_flags |= R_RES1;
00177                 break;
00178 
00179             case '2': /* reserved bit flags */
00180                 idx->tcp_flags |= R_RES2;
00181                 break;
00182 
00183             case '!': /* not, fire if all flags specified are not present,
00184                          other are don't care */
00185                 idx->mode = M_NOT;
00186                 break;
00187             case '*': /* star or any, fire if any flags specified are 
00188                          present, other are don't care */
00189                 idx->mode = M_ANY;
00190                 break;
00191             case '+': /* plus or all, fire if all flags specified are
00192                          present, other are don't care */
00193                 idx->mode = M_ALL;
00194                 break;
00195             case ',':
00196                 comma_set = 1;
00197                 break;
00198             default:
00199                 FatalError("%s(%d): bad TCP flag = \"%c\"\n"
00200                            "Valid otions: UAPRSF12 or 0 for NO flags (e.g. NULL scan),"
00201                            " and !, + or * for modifiers\n",
00202                            file_name, file_line, *fptr);
00203         }
00204 
00205         fptr++;
00206     }
00207 
00208     while(isspace((u_char) *fptr))
00209         fptr++;
00210 
00211     
00212     /* create the mask portion now */
00213     while(fptr < fend && comma_set == 1)
00214     {
00215         switch(*fptr)
00216         {
00217             case 'f':
00218             case 'F':
00219                 idx->tcp_mask |= R_FIN;
00220                 break;
00221 
00222             case 's':
00223             case 'S':
00224                 idx->tcp_mask |= R_SYN;
00225                 break;
00226 
00227             case 'r':
00228             case 'R':
00229                 idx->tcp_mask |= R_RST;
00230                 break;
00231 
00232             case 'p':
00233             case 'P':
00234                 idx->tcp_mask |= R_PSH;
00235                 break;
00236                 
00237             case 'a':
00238             case 'A':
00239                 idx->tcp_mask |= R_ACK;
00240                 break;
00241                 
00242             case 'u':
00243             case 'U':
00244                 idx->tcp_mask |= R_URG;
00245                 break;
00246                 
00247             case '1': /* reserved bit flags */
00248                 idx->tcp_mask |= R_RES1;
00249                 break;
00250 
00251             case '2': /* reserved bit flags */
00252                 idx->tcp_mask |= R_RES2;
00253                 break;
00254             default:
00255                 FatalError(" Line %s (%d): bad TCP flag = \"%c\"\n  Valid otions: UAPRS12 \n",
00256                            file_name, file_line, *fptr);
00257         }
00258 
00259         fptr++;
00260     }
00261 }
00262 
00263 
00264 int CheckTcpFlags(Packet *p, struct _OptTreeNode *otn_idx, OptFpList *fp_list)
00265 {
00266     TCPFlagCheckData *flagptr;
00267     u_char tcp_flags;
00268 
00269     
00270     flagptr = otn_idx->ds_list[PLUGIN_TCP_FLAG_CHECK];
00271 
00272     if(!p->tcph)
00273     {
00274         /* if error appeared when tcp header was processed,
00275          * test fails automagically */
00276         return 0; 
00277     }
00278 
00279     /* the flags we really want to check are all the ones
00280      */
00281 
00282     tcp_flags = p->tcph->th_flags & (0xFF ^ flagptr->tcp_mask);
00283 
00284     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "           <!!> CheckTcpFlags: "););
00285 
00286     switch((flagptr->mode))
00287     {
00288         case M_NORMAL:
00289             if(flagptr->tcp_flags == tcp_flags) /* only these set */
00290             {
00291                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got TCP [default] flag match!\n"););
00292                 return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
00293             }
00294             else
00295             {
00296                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"No match\n"););
00297             }
00298             break;
00299 
00300         case M_ALL:
00301             /* all set */
00302             if((flagptr->tcp_flags & tcp_flags) == flagptr->tcp_flags)
00303             {
00304                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Got TCP [ALL] flag match!\n"););
00305                 return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
00306             }
00307             else
00308             {
00309                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"No match\n"););
00310             }
00311             break;
00312 
00313         case M_NOT:
00314             if((flagptr->tcp_flags & tcp_flags) == 0)  /* none set */
00315             {
00316                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got TCP [NOT] flag match!\n"););
00317                 return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
00318             }
00319             else
00320             {
00321                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "No match\n"););
00322             }
00323             break;
00324 
00325         case M_ANY:
00326             if((flagptr->tcp_flags & tcp_flags) != 0)  /* something set */
00327             {
00328                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got TCP [ANY] flag match!\n"););
00329                 return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
00330             }
00331             else
00332             {
00333                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"No match\n"););
00334             }
00335             break;
00336 
00337         default:  /* Should never see this */
00338             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "TCP flag check went to default case"
00339                                     " for some silly reason\n"););
00340             break;
00341     }
00342 
00343     return 0;
00344 }
00345 

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