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

sp_pattern_match.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 #include <errno.h>
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025 
00026 #ifdef HAVE_STRINGS_H
00027 #include <strings.h>
00028 #endif
00029 
00030 #ifdef DEBUG
00031 #include <assert.h>
00032 #endif
00033 
00034 #include "sp_pattern_match.h"
00035 #include "bounds.h"
00036 #include "rules.h"
00037 #include "plugbase.h"
00038 #include "debug.h"
00039 #include "mstring.h"
00040 #include "util.h" 
00041 #include "parser.h"  /* why does parser.h define Add functions.. */
00042 #include "plugin_enum.h"
00043 #include "checksum.h"
00044 #include "inline.h"
00045 
00046 static void PayloadSearchInit(char *, OptTreeNode *, int);
00047 static void PayloadSearchListInit(char *, OptTreeNode *, int);
00048 static void ParseContentListFile(char *, OptTreeNode *, int);
00049 static void PayloadSearchUri(char *, OptTreeNode *, int);
00050 static void ParsePattern(char *, OptTreeNode *, int);
00051 static int CheckANDPatternMatch(Packet *, struct _OptTreeNode *, OptFpList *);
00052 static int CheckORPatternMatch(Packet *, struct _OptTreeNode *, OptFpList *);
00053 static int CheckUriPatternMatch(Packet *, struct _OptTreeNode *, OptFpList *);
00054 static void PayloadSearchOffset(char *, OptTreeNode *, int);
00055 static void PayloadSearchDepth(char *, OptTreeNode *, int);
00056 static void PayloadSearchNocase(char *, OptTreeNode *, int);
00057 static void PayloadSearchRegex(char *, OptTreeNode *, int);
00058 static void PayloadSearchDistance(char *, OptTreeNode *, int);
00059 static void PayloadSearchWithin(char *, OptTreeNode *, int);
00060 static void PayloadSearchRawbytes(char *, OptTreeNode *, int);
00061 static void PayloadReplaceInit(char *, OptTreeNode *, int);
00062 static PatternMatchData * ParseReplacePattern(char *, OptTreeNode *);
00063 int PayloadReplace(Packet *, struct _OptTreeNode *, OptFpList *, int
00064                          depth);
00065 static int uniSearchReal(char *data, int dlen, PatternMatchData *pmd, int nocase);
00066 
00067 static PatternMatchData * NewNode(OptTreeNode *, int);
00068 void PayloadSearchCompile();
00069 
00070 int list_file_line;     /* current line being processed in the list file */
00071 int lastType = PLUGIN_PATTERN_MATCH;
00072 u_int8_t *doe_ptr;
00073 
00074 int detect_depth;       /* depth to the first char of the match */
00075 
00076 extern HttpUri UriBufs[URI_COUNT]; /* the set of buffers that we are using to match against
00077                                       set in decode.c */
00078 extern u_int8_t DecodeBuffer[DECODE_BLEN];
00079 
00080 extern char *file_name;
00081 extern int file_line;
00082 
00083 
00084 void SetupPatternMatch()
00085 {
00086     RegisterPlugin("content", PayloadSearchInit);
00087     RegisterPlugin("content-list", PayloadSearchListInit);
00088     RegisterPlugin("offset", PayloadSearchOffset);
00089     RegisterPlugin("depth", PayloadSearchDepth);
00090     RegisterPlugin("nocase", PayloadSearchNocase);
00091     RegisterPlugin("rawbytes", PayloadSearchRawbytes);
00092     RegisterPlugin("regex", PayloadSearchRegex);
00093     RegisterPlugin("uricontent", PayloadSearchUri);
00094     RegisterPlugin("distance", PayloadSearchDistance);
00095     RegisterPlugin("within", PayloadSearchWithin);
00096     RegisterPlugin("replace", PayloadReplaceInit);
00097 
00098     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00099                 "Plugin: PatternMatch Initialized!\n"););
00100 }
00101 
00102 void PayloadReplaceInit(char *data, OptTreeNode * otn, int protocol)
00103 {
00104     PatternMatchData *idx;
00105     PatternMatchData *test_idx;
00106 
00107     if(!InlineMode())
00108         return;
00109     
00110     idx = (PatternMatchData *) otn->ds_list[PLUGIN_PATTERN_MATCH];
00111 
00112     if(idx == NULL)
00113     {
00114         FatalError("ERROR %s Line %d => Please place \"content\" rules "
00115                    "before depth, nocase, replace or offset modifiers.\n",
00116                    file_name, file_line);
00117     }
00118 
00119     test_idx = ParseReplacePattern(data, otn);
00120 #ifdef DEBUG
00121     printf("idx (%p) pattern_size (%d) replace_size (%d)\n", test_idx, 
00122                     test_idx->pattern_size, test_idx->replace_size);
00123 #endif
00124     if (test_idx && test_idx->pattern_size != test_idx->replace_size)
00125     {
00126         FatalError("ERROR %s Line %d => The length of the replacement "
00127                    "string must be the same length as the content string.\n",
00128                    file_name, file_line);
00129     }
00130 
00131 #ifdef DEBUG
00132     printf("PayLoadReplaceInit Added to rule!\n");
00133 #endif
00134 }
00135 
00136 /*************************************************************************/
00137 /*                                                                       */
00138 /*  Sigh.... this should be part of ParsePattern, but that can wait      */
00139 /*                                                                       */
00140 /*************************************************************************/
00141 
00142 PatternMatchData * ParseReplacePattern(char *rule, OptTreeNode * otn)
00143 {
00144     unsigned char tmp_buf[2048];
00145 
00146     /* got enough ptrs for you? */
00147     char *start_ptr;
00148     char *end_ptr;
00149     char *idx;
00150     char *dummy_idx;
00151     char *dummy_end;
00152     char hex_buf[3];
00153     u_int dummy_size = 0;
00154     int size;
00155     int hexmode = 0;
00156     int hexsize = 0;
00157     int pending = 0;
00158     int cnt = 0;
00159     int literal = 0;
00160     int exception_flag = 0;
00161     PatternMatchData *ds_idx;
00162 
00163     /* clear out the temp buffer */
00164     bzero(tmp_buf, 2048);
00165 
00166     while(isspace((int)*rule))
00167         rule++;
00168 
00169     if(*rule == '!')
00170     {
00171         exception_flag = 1;
00172     }
00173 
00174     /* find the start of the data */
00175     start_ptr = index(rule, '"');
00176 
00177     if(start_ptr == NULL)
00178     {
00179         FatalError("ERROR %s Line %d => Replace data needs to be "
00180                    "enclosed in quotation marks (\")!\n",
00181                    file_name, file_line);
00182     }
00183 
00184     /* move the start up from the beggining quotes */
00185     start_ptr++;
00186 
00187     /* find the end of the data */
00188     end_ptr = strrchr(start_ptr, '"');
00189 
00190     if(end_ptr == NULL)
00191     {
00192         FatalError("ERROR %s Line %d => Replace data needs to be enclosed "
00193                    "in quotation marks (\")!\n", file_name, file_line);
00194     }
00195 
00196     /* set the end to be NULL */
00197     *end_ptr = '\0';
00198 
00199     /* how big is it?? */
00200     size = end_ptr - start_ptr;
00201 
00202     /* uh, this shouldn't happen */
00203     if(size <= 0)
00204     {
00205         FatalError("ERROR %s Line %d => Bad pattern length!\n",
00206                    file_name, file_line);
00207     }
00208     /* set all the pointers to the appropriate places... */
00209     idx = start_ptr;
00210 
00211     /* set the indexes into the temp buffer */
00212     dummy_idx = tmp_buf;
00213     dummy_end = (dummy_idx + size);
00214 
00215     /* why is this buffer so small? */
00216     bzero(hex_buf, 3);
00217     memset(hex_buf, '0', 2);
00218 
00219     /* BEGIN BAD JUJU..... */
00220     while(idx < end_ptr)
00221     {
00222         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "processing char: %c\n", *idx););
00223 
00224         switch(*idx)
00225         {
00226             case '|':
00227                     
00228                 DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Got bar... "););
00229                 
00230                 if(!literal)
00231                 {
00232                         
00233                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER,
00234                                             "not in literal mode... "););
00235                     
00236                     if(!hexmode)
00237                     {
00238                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00239                                                 "Entering hexmode\n"););
00240 
00241                         hexmode = 1;
00242                     }
00243                     else
00244                     {
00245                             
00246                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00247                                                 "Exiting hexmode\n"););
00248                         
00249                         hexmode = 0;
00250                         pending = 0;
00251                     }
00252 
00253                     if(hexmode)
00254                         hexsize = 0;
00255                 }
00256                 else
00257                 {
00258 
00259                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00260                                             "literal set, Clearing\n"););
00261 
00262                     literal = 0;
00263                     tmp_buf[dummy_size] = start_ptr[cnt];
00264                     dummy_size++;
00265                 }
00266 
00267                 break;
00268 
00269             case '\\':
00270                 
00271                 DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Got literal char... "););
00272 
00273                 if(!literal)
00274                 {
00275                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00276                                             "Setting literal\n"););
00277                     
00278                     literal = 1;
00279                 }
00280                 else
00281                 {
00282                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00283                                             "Clearing literal\n"););
00284                     
00285                     tmp_buf[dummy_size] = start_ptr[cnt];
00286                     literal = 0;
00287                     dummy_size++;
00288                 }
00289                 break;
00290 
00291             default:
00292                 if(hexmode)
00293                 {
00294                     if(isxdigit((int) *idx))
00295                     {
00296                         hexsize++;
00297 
00298                         if(!pending)
00299                         {
00300                             hex_buf[0] = *idx;
00301                             pending++;
00302                         }
00303                         else
00304                         {
00305                             hex_buf[1] = *idx;
00306                             pending--;
00307 
00308                             if(dummy_idx < dummy_end)
00309                             {
00310                                 tmp_buf[dummy_size] = (u_char)
00311                                     strtol(hex_buf, (char **) NULL, 16)&0xFF;
00312 
00313                                 dummy_size++;
00314                                 bzero(hex_buf, 3);
00315                                 memset(hex_buf, '0', 2);
00316                             }
00317                             else
00318                             {
00319                                 FatalError("ERROR => ParsePattern() dummy "
00320                                            "buffer overflow, make a smaller "
00321                                            "pattern please! (Max size = 2048)\n");
00322                             }
00323                         }
00324                     }
00325                     else
00326                     {
00327                         if(*idx != ' ')
00328                         {
00329                             FatalError("ERROR Line %d => What is this "
00330                                        "\"%c\"(0x%X) doing in your binary "
00331                                        "buffer? Valid hex values only please! "
00332                                        "(0x0 -0xF) Position: %d\n",
00333                                        file_line, (char) *idx, (char) *idx, cnt);
00334                         }
00335                     }
00336                 }
00337                 else
00338                 {
00339                     if(*idx >= 0x1F && *idx <= 0x7e)
00340                     {
00341                         if(dummy_idx < dummy_end)
00342                         {
00343                             tmp_buf[dummy_size] = start_ptr[cnt];
00344                             dummy_size++;
00345                         }
00346                         else
00347                         {
00348                             FatalError("ERROR Line %d=> ParsePattern() dummy "
00349                                        "buffer overflow!\n", file_line);
00350                         }
00351 
00352                         if(literal)
00353                         {
00354                             literal = 0;
00355                         }
00356                     }
00357                     else
00358                     {
00359                         if(literal)
00360                         {
00361                             tmp_buf[dummy_size] = start_ptr[cnt];
00362                             dummy_size++;
00363                             
00364                             DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00365                                                     "Clearing literal\n"););
00366                             
00367                             literal = 0;
00368                         }
00369                         else
00370                         {
00371                             FatalError("%s(%d)=> character value out "
00372                                        "of range, only hex characters allowed in binary content buffers\n",
00373                                        file_name, file_line);
00374                         }
00375                     }
00376                 }
00377 
00378                 break;                          
00379 
00380         } /* end switch */
00381 
00382         dummy_idx++;
00383         idx++;
00384         cnt++;
00385     }
00386     /* ...END BAD JUJU */
00387 
00388     /* error prunning */
00389 
00390     if (literal) {
00391         FatalError("%s(%d)=> backslash escape is not "
00392                    "completed\n", file_name, file_line);
00393     }
00394     if (hexmode) {
00395         FatalError("%s(%d)=> hexmode is not "
00396                    "completed\n", file_name, file_line);
00397     }
00398     ds_idx = (PatternMatchData *) otn->ds_list[PLUGIN_PATTERN_MATCH];
00399 
00400     while(ds_idx->next != NULL)
00401         ds_idx = ds_idx->next;
00402 
00403     if((ds_idx->replace_buf = (char *) calloc(dummy_size+1,
00404                                                   sizeof(char))) == NULL)
00405     {
00406         FatalError("ERROR => ParsePattern() pattern_buf malloc filed!\n");
00407     }
00408 
00409     //memcpy(ds_idx->replace_buf, tmp_buf, dummy_size);
00410     SafeMemcpy(ds_idx->replace_buf, tmp_buf, dummy_size, 
00411                ds_idx->replace_buf, (ds_idx->replace_buf+dummy_size+1));
00412 
00413     ds_idx->replace_size = dummy_size;
00414 
00415     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, 
00416                             "ds_idx (%p) replace_size(%d) replace_buf(%s)\n", ds_idx,
00417                             ds_idx->replace_size, ds_idx->replace_buf););
00418 
00419     return ds_idx;
00420 }
00421 
00422 int PayloadReplace(Packet *p, struct _OptTreeNode *otn,
00423                          OptFpList *fp_list, int depth)
00424 {
00425     struct pseudoheader
00426     {
00427         u_int32_t sip, dip;
00428         u_int8_t zero;
00429         u_int8_t protocol;
00430         u_int16_t len;
00431     };
00432 
00433     PatternMatchData *idx;
00434     struct pseudoheader ph;
00435     unsigned int ip_len;
00436     unsigned int hlen;
00437 
00438     //idx = (PatternMatchData *)otn->ds_list[PLUGIN_PATTERN_MATCH];
00439     idx = (PatternMatchData *)fp_list->context;
00440 
00441     if (depth >= 0)
00442     {
00443         //memcpy(p->data+depth, idx->replace_buf, strlen(idx->replace_buf));
00444         SafeMemcpy( (p->data + depth), idx->replace_buf, strlen(idx->replace_buf), 
00445         p->data, (p->data + p->dsize + 1) );
00446 
00447 #ifdef GIDS
00448         InlineReplace();
00449 #endif
00450 
00451         /* calculate new checksum */
00452         p->iph->ip_csum=0;
00453         hlen = IP_HLEN(p->iph) << 2;
00454         ip_len=ntohs(p->iph->ip_len);
00455         ip_len -= hlen;
00456         p->iph->ip_csum = in_chksum_ip((u_short *)p->iph, hlen);
00457 
00458         if (p->tcph)
00459         {
00460             p->tcph->th_sum = 0;
00461             ph.sip = (u_int32_t)(p->iph->ip_src.s_addr);
00462             ph.dip = (u_int32_t)(p->iph->ip_dst.s_addr);
00463             ph.zero = 0;
00464             ph.protocol = p->iph->ip_proto;
00465             ph.len = htons((u_short)ip_len);
00466             p->tcph->th_sum = in_chksum_tcp((u_short *)&ph,
00467                                             (u_short *)(p->tcph), ip_len);
00468         }
00469         else if (p->udph)
00470         {
00471             p->udph->uh_chk = 0;
00472             ph.sip = (u_int32_t)(p->iph->ip_src.s_addr);
00473             ph.dip = (u_int32_t)(p->iph->ip_dst.s_addr);
00474             ph.zero = 0;
00475             ph.protocol = p->iph->ip_proto;
00476             ph.len = htons((u_short)ip_len);
00477             p->udph->uh_chk = in_chksum_udp((u_short *)&ph,
00478                                             (u_short *)(p->udph), ip_len);
00479         }
00480         else if (p->icmph)
00481         {
00482             p->icmph->csum = 0;
00483             ph.sip = (u_int32_t)(p->iph->ip_src.s_addr);
00484             ph.dip = (u_int32_t)(p->iph->ip_dst.s_addr);
00485             ph.zero = 0;
00486             ph.protocol = p->iph->ip_proto;
00487             ph.len = htons((u_short)ip_len);
00488             p->icmph->csum = in_chksum_icmp((u_int16_t *)(p->icmph), ip_len);
00489         }
00490     }
00491 
00492     return 1;
00493 }
00494 
00495 static inline int computeDepth(int dlen, PatternMatchData * pmd) 
00496 {
00497     /* do some tests to make sure we stay in bounds */
00498     if((pmd->depth + pmd->offset) > dlen)
00499     {
00500         /* we want to check only depth bytes anyway */
00501         int sub_depth = dlen - pmd->offset; 
00502 
00503         if((sub_depth > 0) && (sub_depth >= (int)pmd->pattern_size))
00504         {
00505             return  sub_depth;
00506         }
00507         else
00508         {
00509             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00510                         "Pattern Match failed -- sub_depth: %d < "
00511                         "(int)pmd->pattern_size: %d!\n",
00512                         sub_depth, (int)pmd->pattern_size););
00513 
00514             return -1;
00515         }
00516     }
00517     else
00518     {      
00519         if(pmd->depth && (dlen - pmd->offset > pmd->depth))
00520         {
00521             return pmd->depth;
00522         }
00523         else
00524         {
00525             return dlen - pmd->offset;
00526         }
00527     }
00528 }
00529 
00530 /*
00531  * Figure out how deep the into the packet from the base_ptr we can go
00532  *
00533  * base_ptr = the offset into the payload relative to the last match plus the offset
00534  *            contained within the current pmd
00535  *
00536  * dlen = amount of data in the packet from the base_ptr to the end of the packet
00537  *
00538  * pmd = the patterm match data struct for this test
00539  */
00540 static inline int computeWithin(int dlen, PatternMatchData *pmd)
00541 {
00542     /* do we want to check more bytes than there are in the buffer? */
00543     if(pmd->within > dlen)
00544     {
00545         /* should we just return -1 here since the data might actually be within 
00546          * the stream but not the current packet's payload?
00547          */
00548         
00549         /* if the buffer size is greater than the size of the pattern to match */
00550         if(dlen >= (int)pmd->pattern_size)
00551         {
00552             /* return the size of the buffer */
00553             return dlen;
00554         }
00555         else
00556         {
00557             /* failed, pattern size is greater than number of bytes in the buffer */
00558             return -1;
00559         }
00560     }
00561 
00562     /* the within vaule is in range of the number of buffer bytes */
00563     return pmd->within;
00564 }
00565 
00566 
00567 static int uniSearchREG(char * data, int dlen, PatternMatchData * pmd)
00568 {
00569     int depth = computeDepth(dlen, pmd);
00570     /* int distance_adjustment = 0;
00571      *  int depth_adjustment = 0;
00572      */
00573     int success = 0;
00574 
00575     if (depth < 0)
00576         return 0;
00577 
00578     /* XXX DESTROY ME */
00579     /*success =  mSearchREG(data + pmd->offset + distance_adjustment, 
00580             depth_adjustment!=0?depth_adjustment:depth, 
00581             pmd->pattern_buf, pmd->pattern_size, pmd->skip_stride, 
00582             pmd->shift_stride);*/
00583 
00584     return success;
00585 }
00586 
00587 
00588 
00589 /* 
00590  * case sensitive search
00591  *
00592  * data = ptr to buffer to search
00593  * dlen = distance to the back of the buffer being tested, validated 
00594  *        against offset + depth before function entry (not distance/within)
00595  * pmd = pointer to pattern match data struct
00596  */
00597 
00598 static int uniSearch(char *data, int dlen, PatternMatchData *pmd)
00599 {
00600     return uniSearchReal(data, dlen, pmd, 0);
00601 }
00602 
00603 /* 
00604  * case insensitive search
00605  *
00606  * data = ptr to buffer to search
00607  * dlen = distance to the back of the buffer being tested, validated 
00608  *        against offset + depth before function entry (not distance/within)
00609  * pmd = pointer to pattern match data struct
00610  */
00611 static int uniSearchCI(char *data, int dlen, PatternMatchData *pmd)
00612 {
00613     return uniSearchReal(data, dlen, pmd, 1);
00614 }
00615 
00616 
00617 /* 
00618  * single search function. 
00619  *
00620  * data = ptr to buffer to search
00621  * dlen = distance to the back of the buffer being tested, validated 
00622  *        against offset + depth before function entry (not distance/within)
00623  * pmd = pointer to pattern match data struct
00624  * nocase = 0 means case sensitve, 1 means case insensitive
00625  */       
00626 static int uniSearchReal(char *data, int dlen, PatternMatchData *pmd, int nocase)
00627 {
00628     /* 
00629      * in theory computeDepth doesn't need to be called because the 
00630      * depth + offset adjustments have been made by the calling function
00631      */
00632     int depth = dlen;
00633     int old_depth = dlen;
00634     int success = 0;
00635     char *start_ptr = data;
00636     char *end_ptr = data + dlen;
00637     char *base_ptr = start_ptr;
00638     
00639     DEBUG_WRAP(char *hexbuf;);
00640 
00641 
00642     if(pmd->use_doe != 1)
00643     {
00644         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00645                                 "NOT Using Doe Ptr\n"););
00646         doe_ptr = NULL; /* get rid of all our pattern match state */
00647     }
00648 
00649     /* check to see if we've got a stateful start point */
00650     if(doe_ptr)
00651     {
00652         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00653                                 "Using Doe Ptr\n"););
00654 
00655         base_ptr = doe_ptr;
00656         depth = dlen - ((char *) doe_ptr - data);
00657     }
00658     else
00659     {
00660         base_ptr = start_ptr;
00661         depth = dlen;
00662     }
00663 
00664     /* if we're using a distance call */
00665     if(pmd->distance)
00666     {
00667         /* set the base pointer up for the distance */
00668         base_ptr += pmd->distance;
00669         depth -= pmd->distance;
00670     }
00671     else /* otherwise just use the offset (validated by calling function) */
00672     {
00673         base_ptr += pmd->offset;
00674         depth -= pmd->offset;
00675     }
00676     
00677     if(pmd->within != 0)
00678     {
00679         /* 
00680          * calculate the "real" depth based on the current base and available
00681          * number of bytes in the buffer
00682          *
00683          * this should account for the current base_ptr as it relates to 
00684          * the back of the buffer being tested
00685          */
00686         old_depth = depth;
00687         
00688         depth = computeWithin(depth, pmd);
00689         
00690         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Changing Depth from %d to %d\n", old_depth, depth););
00691     }
00692 
00693     /* make sure we and in range */
00694     if(!inBounds(start_ptr, end_ptr, base_ptr))
00695     {
00696         
00697         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00698                                 "returning because base_ptr"
00699                                 " is out of bounds start_ptr: %p end: %p base: %p\n",
00700                                 start_ptr, end_ptr, base_ptr););
00701         return 0;
00702     }
00703 
00704     if(depth < 0)
00705     {
00706         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00707                                 "returning because depth is negative (%d)\n",
00708                                 depth););
00709         return 0;        
00710     }
00711 
00712     if(depth > dlen)
00713     {
00714         /* if offsets are negative but somehow before the start of the
00715            packet, let's make sure that we get everything going
00716            straight */
00717         depth = dlen;
00718     }
00719 
00720     if((pmd->depth > 0) && (depth > pmd->depth))
00721     {
00722         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00723                                 "Setting new depth to %d from %d\n",
00724                                 pmd->depth, depth););
00725 
00726         depth = pmd->depth;
00727     }
00728     
00729     /* make sure we and in range */
00730     if(!inBounds(start_ptr, end_ptr, base_ptr + depth - 1))
00731     {
00732         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00733                                 "returning because base_ptr + depth - 1"
00734                                 " is out of bounds start_ptr: %p end: %p base: %p\n",
00735                                 start_ptr, end_ptr, base_ptr););
00736         return 0;
00737     }
00738 
00739 #ifdef DEBUG
00740     assert(depth <= old_depth);
00741 
00742     DebugMessage(DEBUG_PATTERN_MATCH, "uniSearchReal:\n ");
00743 
00744     hexbuf = hex(pmd->pattern_buf, pmd->pattern_size);
00745     DebugMessage(DEBUG_PATTERN_MATCH, "   p->data: %p\n   doe_ptr: %p\n   "
00746                  "base_ptr: %p\n   depth: %d\n   searching for: %s\n", 
00747                  data, doe_ptr, base_ptr, depth, hexbuf);
00748     free(hexbuf);
00749 #endif /* DEBUG */
00750     
00751     if(nocase)
00752     {
00753         success = mSearchCI(base_ptr, depth, 
00754                             pmd->pattern_buf,
00755                             pmd->pattern_size,
00756                             pmd->skip_stride, 
00757                             pmd->shift_stride);
00758     }
00759     else
00760     {
00761         success = mSearch(base_ptr, depth,
00762                           pmd->pattern_buf,
00763                           pmd->pattern_size,
00764                           pmd->skip_stride,
00765                           pmd->shift_stride);
00766     }
00767 
00768 
00769 #ifdef DEBUG
00770     if(success)
00771     {
00772         DebugMessage(DEBUG_PATTERN_MATCH, "matched, doe_ptr: %p (%d)\n", 
00773                      doe_ptr, ((char *)doe_ptr - data));
00774     }
00775 #endif
00776 
00777     return success;
00778 }
00779 
00780 
00781 static void make_precomp(PatternMatchData * idx)
00782 {
00783     free(idx->skip_stride);
00784     free(idx->shift_stride);
00785 
00786     idx->skip_stride = make_skip(idx->pattern_buf, idx->pattern_size);
00787 
00788     idx->shift_stride = make_shift(idx->pattern_buf, idx->pattern_size);
00789 }
00790 
00791 void PayloadSearchListInit(char *data, OptTreeNode * otn, int protocol)
00792 {
00793     char *sptr;
00794     char *eptr;
00795 
00796     lastType = PLUGIN_PATTERN_MATCH_OR;
00797 
00798     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchListInit()\n"););
00799 
00800     /* get the path/file name from the data */
00801     while(isspace((int) *data))
00802         data++;
00803 
00804     /* grab everything between the starting " and the end one */
00805     sptr = index(data, '"');
00806     eptr = strrchr(data, '"');
00807 
00808     if(sptr != NULL && eptr != NULL)
00809     {
00810         /* increment past the first quote */
00811         sptr++;
00812 
00813         /* zero out the second one */
00814         *eptr = 0;
00815     }
00816     else
00817     {
00818         sptr = data;
00819     }
00820 
00821     /* read the content keywords from the list file */
00822     ParseContentListFile(sptr, otn, protocol);
00823 
00824 
00825     /* link the plugin function in to the current OTN */
00826     AddOptFuncToList(CheckORPatternMatch, otn);
00827 
00828     return;
00829 }
00830 
00831 
00832 void PayloadSearchInit(char *data, OptTreeNode * otn, int protocol)
00833 {
00834     OptFpList *fpl;
00835     PatternMatchData *pmd;
00836 
00837     lastType = PLUGIN_PATTERN_MATCH;
00838 
00839     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchInit()\n"););
00840 
00841     /* whack a new node onto the list */
00842     pmd = NewNode(otn, PLUGIN_PATTERN_MATCH);
00843     
00844     /* set up the pattern buffer */
00845     ParsePattern(data, otn, PLUGIN_PATTERN_MATCH);
00846 
00847     /* link the plugin function in to the current OTN */
00848     fpl = AddOptFuncToList(CheckANDPatternMatch, otn);
00849 
00850     fpl->context = pmd;
00851 
00852     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00853                 "OTN function PatternMatch Added to rule!\n"););
00854 }
00855 
00856 
00857 
00858 void PayloadSearchUri(char *data, OptTreeNode * otn, int protocol)
00859 {
00860     PatternMatchData * pmd;
00861     OptFpList *fpl;
00862 
00863     lastType = PLUGIN_PATTERN_MATCH_URI;
00864     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchUri()\n"););
00865 
00866     /* whack a new node onto the list */
00867     pmd = NewNode(otn, PLUGIN_PATTERN_MATCH_URI);
00868 
00869     /* set up the pattern buffer */
00870     ParsePattern(data, otn, PLUGIN_PATTERN_MATCH_URI);
00871 
00872 #ifdef PATTERN_FAST
00873     pmd->search = uniSearch;
00874     make_precomp(pmd);
00875 #endif
00876 
00877     /* link the plugin function in to the current OTN */
00878     fpl = AddOptFuncToList(CheckUriPatternMatch, otn);
00879 
00880     fpl->context = pmd;
00881 
00882     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00883                 "OTN function PatternMatch Added to rule!\n"););
00884 }
00885 
00886 
00887 
00888 
00889 void PayloadSearchOffset(char *data, OptTreeNode * otn, int protocol)
00890 {
00891     PatternMatchData *idx;
00892 
00893     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearch()\n"););
00894 
00895     idx = otn->ds_list[lastType];
00896 
00897     if(idx == NULL)
00898     {
00899         FatalError("%s(%d) => Please place \"content\" rules before "
00900                 "depth, nocase or offset modifiers.\n", file_name, file_line);
00901     }
00902 
00903     while(idx->next != NULL)
00904         idx = idx->next;
00905 
00906     while(isspace((int) *data))
00907         data++;
00908 
00909     errno = 0;
00910     
00911     idx->offset = strtol(data, NULL, 10);
00912 
00913     if(errno == ERANGE)
00914     {
00915         FatalError("ERROR %s Line %d => Range problem on offset value\n", 
00916                 file_name, file_line);
00917     }
00918 
00919     if(idx->offset > 65535 || idx->offset < -65535)
00920     {
00921         FatalError("ERROR %s Line %d => Offset greater than max Ipv4 "
00922                 "packet size\n", file_name, file_line);
00923     }
00924 
00925     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Pattern offset = %d\n", 
00926                 idx->offset););
00927 
00928     return;
00929 }
00930 
00931 
00932 
00933 void PayloadSearchDepth(char *data, OptTreeNode * otn, int protocol)
00934 {
00935     PatternMatchData *idx;
00936 
00937     idx = (PatternMatchData *) otn->ds_list[lastType];
00938 
00939     if(idx == NULL)
00940     {
00941         FatalError("ERROR %s Line %d => Please place \"content\" rules "
00942                 "before depth, nocase or offset modifiers.\n", 
00943                 file_name, file_line);
00944     }
00945 
00946     while(idx->next != NULL)
00947         idx = idx->next;
00948 
00949     while(isspace((int) *data))
00950         data++;
00951 
00952     errno = 0;
00953     
00954     idx->depth = strtol(data, NULL, 10);
00955 
00956     if(errno == ERANGE)
00957     {
00958         FatalError("ERROR %s Line %d => Range problem on depth value\n", 
00959                 file_name, file_line);
00960     }
00961 
00962     if(idx->depth > 65535 || idx->depth < -65535)
00963     {
00964         FatalError("ERROR %s Line %d => Depth greater than max Ipv4 "
00965                 "packet size\n", file_name, file_line);
00966     }
00967 
00968     /* check to make sure that this the depth allows this rule to fire */
00969     if(idx->depth != 0 && idx->depth < (int)idx->pattern_size)
00970     {
00971         FatalError("%s(%d) => The depth(%d) is less than the size of the content(%u)!\n",
00972                    file_name, file_line, idx->depth, idx->pattern_size);
00973     }
00974 
00975 
00976     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern depth = %d\n", 
00977                 idx->depth););
00978 
00979     return;
00980 }
00981 
00982 void PayloadSearchNocase(char *data, OptTreeNode * otn, int protocol)
00983 {
00984     PatternMatchData *idx;
00985     int i;
00986 
00987     idx = (PatternMatchData *) otn->ds_list[lastType];
00988 
00989     if(idx == NULL)
00990     {
00991         FatalError("(%s)%d => Please place \"content\" rules before"
00992                    " depth, nocase or offset modifiers.\n", file_name, file_line);
00993     }
00994     while(idx->next != NULL)
00995         idx = idx->next;
00996 
00997     i = idx->pattern_size;
00998 
00999     while(--i >= 0)
01000         idx->pattern_buf[i] = toupper((unsigned char) idx->pattern_buf[i]);
01001 
01002     idx->nocase = 1;
01003 
01004 #ifdef PATTERN_FAST
01005     idx->search = setSearch;
01006 #else
01007     idx->search = uniSearchCI;
01008     make_precomp(idx);
01009 #endif
01010 
01011 
01012     return;
01013 }
01014 
01015 void PayloadSearchRawbytes(char *data, OptTreeNode * otn, int protocol)
01016 {
01017     PatternMatchData *idx;
01018 
01019     idx = (PatternMatchData *) otn->ds_list[lastType];
01020 
01021     if(idx == NULL)
01022     {
01023         FatalError("ERROR Line %d => Please place \"content\" rules before"
01024                 " rawbytes, depth, nocase or offset modifiers.\n", file_line);
01025     }
01026     while(idx->next != NULL)
01027         idx = idx->next;
01028 
01029     /* mark this as inspecting a raw pattern match rather than a
01030        decoded application buffer */
01031     idx->rawbytes = 1;    
01032     return;
01033 }
01034 
01035 void PayloadSearchDistance(char *data, OptTreeNode *otn, int protocol)
01036 {
01037     PatternMatchData *idx;
01038 
01039     idx = (PatternMatchData *) otn->ds_list[lastType];
01040 
01041     if(idx == NULL)
01042     {
01043         FatalError("Error %s(%d) => Distance without context, please place "
01044                 "\"content\" keywords before distance modifiers\n", file_name,
01045                 file_line);
01046     }
01047 
01048     while(idx->next != NULL)
01049         idx = idx->next;
01050 
01051     while(isspace((int) *data))
01052         data++;
01053 
01054 
01055     errno = 0;
01056     
01057     idx->distance = strtol(data, NULL, 10);
01058 
01059     if(errno == ERANGE)
01060     {
01061         FatalError("ERROR %s Line %d => Range problem on distance value\n", 
01062                 file_name, file_line);
01063     }
01064 
01065     if(idx->distance > 65535 || idx->distance < -65535)
01066     {
01067         FatalError("ERROR %s Line %d => Distance greater than max Ipv4 "
01068                 "packet size\n", file_name, file_line);
01069     }
01070 
01071     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern distance = %d\n", 
01072                 idx->distance););
01073 
01074 
01075     if(!SetUseDoePtr(otn))
01076     {
01077         FatalError("%s Line %d => Unable to initialize doe_ptr\n",
01078                    file_name, file_line);
01079     }
01080     
01081     return;
01082 }
01083 
01084 
01085 void PayloadSearchWithin(char *data, OptTreeNode *otn, int protocol)
01086 {
01087     PatternMatchData *idx;
01088 
01089     idx = (PatternMatchData *) otn->ds_list[lastType];
01090 
01091     if(idx == NULL)
01092     {
01093         FatalError("Error %s(%d) => Distance without context, please place "
01094                 "\"content\" keywords before distance modifiers\n", file_name,
01095                 file_line);
01096     }
01097 
01098     while(idx->next != NULL)
01099         idx = idx->next;
01100 
01101     while(isspace((int) *data))
01102         data++;
01103 
01104     errno = 0;
01105     
01106     idx->within = strtol(data, NULL, 10);
01107     
01108     if(errno == ERANGE)
01109     {
01110         FatalError("ERROR %s Line %d => Range problem on within value\n", 
01111                 file_name, file_line);
01112     }
01113 
01114     if(idx->within > 65535 || idx->within < -65535)
01115     {
01116         FatalError("ERROR %s Line %d => Within greater than max Ipv4 "
01117                 "packet size\n", file_name, file_line);
01118     }
01119 
01120     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern within = %d\n", 
01121                 idx->within););
01122 
01123     
01124     if(!SetUseDoePtr(otn))
01125     {
01126         FatalError("%s Line %d => Unable to initialize doe_ptr\n",
01127                    file_name, file_line);
01128     }
01129 
01130     return;
01131 }
01132 
01133 
01134 
01135 void PayloadSearchRegex(char *data, OptTreeNode * otn, int protocol)
01136 {
01137     PatternMatchData *idx;
01138     int i;
01139 
01140     FatalError("%s(%d) => Sorry, regex isn't supported at this time. "
01141                "This isn't new.", file_name,file_line);
01142 
01143     idx = (PatternMatchData *) otn->ds_list[lastType];
01144 
01145     if(idx == NULL)
01146     {
01147         FatalError("%s(%d) => Please place \"content\" rules "
01148                    "before regex modifiers.\n", file_name, file_line);
01149     }
01150 
01151     while(idx->next != NULL)
01152         idx = idx->next;
01153 
01154     idx->search = uniSearchREG;
01155 
01156     i = idx->pattern_size;
01157 
01158     make_precomp(idx);
01159 
01160     return;
01161 }
01162 
01163 
01164 
01165 
01166 static PatternMatchData * NewNode(OptTreeNode * otn, int type)
01167 {
01168     PatternMatchData *idx;
01169 
01170     idx = (PatternMatchData *) otn->ds_list[type];
01171 
01172     if(idx == NULL)
01173     {
01174         if((otn->ds_list[type] = 
01175                     (PatternMatchData *) calloc(sizeof(PatternMatchData), 
01176                                                 sizeof(char))) == NULL)
01177         {
01178             FatalError("sp_pattern_match NewNode() calloc failed!\n");
01179         }
01180         
01181         return otn->ds_list[type];
01182     }
01183     else
01184     {
01185         idx = otn->ds_list[type];
01186 
01187         while(idx->next != NULL)
01188             idx = idx->next;
01189 
01190         if((idx->next = (PatternMatchData *) 
01191                     calloc(sizeof(PatternMatchData), sizeof(char))) == NULL)
01192         {
01193             FatalError("sp_pattern_match NewNode() calloc failed!\n");
01194         }
01195 
01196         return idx->next;
01197     }
01198 }
01199 
01200 /* This is an exported function that sets
01201  * PatternMatchData->use_doe so that when 
01202  *
01203  * distance, within, byte_jump, byte_test are used, they can make the
01204  * pattern matching functions "keep state" WRT the current packet.
01205  */
01206 int SetUseDoePtr(OptTreeNode * otn)
01207 {
01208     PatternMatchData *idx;
01209 
01210     idx = (PatternMatchData *) otn->ds_list[PLUGIN_PATTERN_MATCH];
01211 
01212     if(idx == NULL)
01213     {
01214 /* Visual C++ 6.0 is -supposed- to have a __FUNCTION__, however
01215  * it was just causing compile errors here.  So, hack around it.
01216  */
01217 #ifdef WIN32
01218 #define __FUNCTION__ "SetUseDoePtr"
01219 #endif
01220         LogMessage("%s: No pattern match data found\n", __FUNCTION__);
01221 #ifdef WIN32
01222 #undef __FUNCTION__
01223 #endif
01224 
01225         return 0;
01226     }
01227     else
01228     {
01229         /* Walk the linked list of content checks */
01230         while(idx->next != NULL)
01231         {
01232             idx = idx->next;
01233         }
01234 
01235         idx->use_doe = 1;
01236         return 1;
01237     }
01238 }
01239 
01240 
01241 /****************************************************************************
01242  *
01243  * Function: GetMaxJumpSize(char *, int)
01244  *
01245  * Purpose: Find the maximum number of characters we can jump ahead
01246  *          from the current offset when checking for this pattern again.
01247  *
01248  * Arguments: data => the pattern string
01249  *            data_len => length of pattern string
01250  *
01251  * Returns: int => number of bytes before pattern repeats within itself
01252  *
01253  ***************************************************************************/
01254 static unsigned int GetMaxJumpSize(char *data, int data_len)
01255 {
01256     int i, j;
01257     
01258     j = 0;
01259     for ( i = 1; i < data_len; i++ )
01260     {
01261         if ( data[j] != data[i] )
01262         {
01263             j = 0;
01264             continue;
01265         }
01266         if ( i == (data_len - 1) )
01267         {
01268             return (data_len - j - 1);
01269         }
01270         j++;
01271     }
01272     return data_len;
01273 }
01274 
01275 
01276 /****************************************************************************
01277  *
01278  * Function: ParsePattern(char *)
01279  *
01280  * Purpose: Process the application layer patterns and attach them to the
01281  *          appropriate rule.  My god this is ugly code.
01282  *
01283  * Arguments: rule => the pattern string
01284  *
01285  * Returns: void function
01286  *
01287  ***************************************************************************/
01288 static void ParsePattern(char *rule, OptTreeNode * otn, int type)
01289 {
01290     unsigned char tmp_buf[2048];
01291 
01292     /* got enough ptrs for you? */
01293     char *start_ptr;
01294     char *end_ptr;
01295     char *idx;
01296     char *dummy_idx;
01297     char *dummy_end;
01298     char *tmp;
01299     char hex_buf[3];
01300     u_int dummy_size = 0;
01301     int size;
01302     int hexmode = 0;
01303     int hexsize = 0;
01304     int pending = 0;
01305     int cnt = 0;
01306     int literal = 0;
01307     int exception_flag = 0;
01308     PatternMatchData *ds_idx;
01309 
01310     /* clear out the temp buffer */
01311     bzero(tmp_buf, 2048);
01312 
01313     if(rule == NULL)
01314     {
01315         FatalError("%s(%d) => ParsePattern Got Null "
01316                    "enclosed in quotation marks (\")!\n", 
01317                    file_name, file_line);
01318     }
01319 
01320     while(isspace((int)*rule))
01321         rule++;
01322 
01323     if(*rule == '!')
01324     {
01325         exception_flag = 1;
01326     }
01327 
01328     /* find the start of the data */
01329     start_ptr = index(rule, '"');
01330 
01331     if(start_ptr == NULL)
01332     {
01333         FatalError("%s(%d) => Content data needs to be "
01334                    "enclosed in quotation marks (\")!\n", 
01335                    file_name, file_line);
01336     }
01337 
01338     /* move the start up from the beggining quotes */
01339     start_ptr++;
01340 
01341     /* find the end of the data */
01342     end_ptr = strrchr(start_ptr, '"');
01343 
01344     if(end_ptr == NULL)
01345     {
01346         FatalError("%s(%d) => Content data needs to be enclosed "
01347                    "in quotation marks (\")!\n", file_name, file_line);
01348     }
01349 
01350     /* Move the null termination up a bit more */
01351     *end_ptr = '\0';
01352 
01353     /* Is there anything other than whitespace after the trailing
01354      * double quote? */
01355     tmp = end_ptr + 1;
01356     while (*tmp != '\0' && isspace ((int)*tmp))
01357         tmp++;
01358 
01359     if (strlen (tmp) > 0)
01360     {
01361         FatalError("%s(%d) => Bad data (possibly due to missing semicolon) "
01362                    "after trailing double quote.",
01363                    file_name, file_line, end_ptr + 1);
01364     }
01365 
01366     /* how big is it?? */
01367     size = end_ptr - start_ptr;
01368 
01369     /* uh, this shouldn't happen */
01370     if(size <= 0)
01371     {
01372         FatalError("%s(%d) => Bad pattern length!\n", 
01373                    file_name, file_line);
01374     }
01375     /* set all the pointers to the appropriate places... */
01376     idx = start_ptr;
01377 
01378     /* set the indexes into the temp buffer */
01379     dummy_idx = tmp_buf;
01380     dummy_end = (dummy_idx + size);
01381 
01382     /* why is this buffer so small? */
01383     bzero(hex_buf, 3);
01384     memset(hex_buf, '0', 2);
01385 
01386     /* BEGIN BAD JUJU..... */
01387     while(idx < end_ptr)
01388     {
01389         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "processing char: %c\n", *idx););
01390         switch(*idx)
01391         {
01392             case '|':
01393                 DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Got bar... "););
01394                 if(!literal)
01395                 {
01396                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "not in literal mode... "););
01397                     if(!hexmode)
01398                     {
01399                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Entering hexmode\n"););
01400                         hexmode = 1;
01401                     }
01402                     else
01403                     {
01404                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Exiting hexmode\n"););
01405 
01406                         /*
01407                         **  Hexmode is not even.
01408                         */
01409                         if(!hexsize || hexsize % 2)
01410                         {
01411                             FatalError("%s(%d) => Content hexmode argument has invalid "
01412                                        "number of hex digits.  The argument '%s' must "
01413                                        "contain a full even byte string.\n",
01414                                        file_name, file_line, start_ptr);
01415                         }
01416 
01417                         hexmode = 0;
01418                         pending = 0;
01419                     }
01420 
01421                     if(hexmode)
01422                         hexsize = 0;
01423                 }
01424                 else
01425                 {
01426                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "literal set, Clearing\n"););
01427                     literal = 0;
01428                     tmp_buf[dummy_size] = start_ptr[cnt];
01429                     dummy_size++;
01430                 }
01431 
01432                 break;
01433 
01434             case '\\':
01435                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Got literal char... "););
01436 
01437                 if(!literal)
01438                 {
01439                     /* Make sure the next char makes this a valid
01440                      * escape sequence.
01441                      */
01442                     if (idx [1] != '\0' && strchr ("\\\":;", idx [1]) == NULL)
01443                     {
01444                         FatalError("%s(%d) => bad escape sequence starting "
01445                                    "with \"%s\". ", file_name, file_line, idx);
01446                     }
01447 
01448                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Setting literal\n"););
01449 
01450                     literal = 1;
01451                 }
01452                 else
01453                 {
01454                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Clearing literal\n"););
01455                     tmp_buf[dummy_size] = start_ptr[cnt];
01456                     literal = 0;
01457                     dummy_size++;
01458                 }
01459 
01460                 break;
01461             case '"':
01462                 if (!literal) {
01463                     FatalError("%s(%d) => Non-escaped "
01464                             " '\"' character!\n", file_name, file_line);
01465                 }
01466                 /* otherwise process the character as default */
01467             default:
01468                 if(hexmode)
01469                 {
01470                     if(isxdigit((int) *idx))
01471                     {
01472                         hexsize++;
01473 
01474                         if(!pending)
01475                         {
01476                             hex_buf[0] = *idx;
01477                             pending++;
01478                         }
01479                         else
01480                         {
01481                             hex_buf[1] = *idx;
01482                             pending--;
01483 
01484                             if(dummy_idx < dummy_end)
01485                             {                            
01486                                 tmp_buf[dummy_size] = (u_char) 
01487                                     strtol(hex_buf, (char **) NULL, 16)&0xFF;
01488 
01489                                 dummy_size++;
01490                                 bzero(hex_buf, 3);
01491                                 memset(hex_buf, '0', 2);
01492                             }
01493                             else
01494                             {
01495                                 FatalError("ParsePattern() dummy "
01496                                         "buffer overflow, make a smaller "
01497                                         "pattern please! (Max size = 2048)\n");
01498                             }
01499                         }
01500                     }
01501                     else
01502                     {
01503                         if(*idx != ' ')
01504                         {
01505                             FatalError("%s(%d) => What is this "
01506                                     "\"%c\"(0x%X) doing in your binary "
01507                                     "buffer?  Valid hex values only please! "
01508                                     "(0x0 - 0xF) Position: %d\n",
01509                                     file_name, 
01510                                     file_line, (char) *idx, (char) *idx, cnt);
01511                         }
01512                     }
01513                 }
01514                 else
01515                 {
01516                     if(*idx >= 0x1F && *idx <= 0x7e)
01517                     {
01518                         if(dummy_idx < dummy_end)
01519                         {
01520                             tmp_buf[dummy_size] = start_ptr[cnt];
01521                             dummy_size++;
01522                         }
01523                         else
01524                         {
01525                             FatalError("%s(%d)=> ParsePattern() "
01526                                     "dummy buffer overflow!\n", file_name, file_line);
01527                         }
01528 
01529                         if(literal)
01530                         {
01531                             literal = 0;
01532                         }
01533                     }
01534                     else
01535                     {
01536                         if(literal)
01537                         {
01538                             tmp_buf[dummy_size] = start_ptr[cnt];
01539                             dummy_size++;
01540                             DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Clearing literal\n"););
01541                             literal = 0;
01542                         }
01543                         else
01544                         {
01545                             FatalError("%s(%d)=> character value out "
01546                                     "of range, try a binary buffer\n", 
01547                                     file_name, file_line);
01548                         }
01549                     }
01550                 }
01551 
01552                 break;
01553         }
01554 
01555         dummy_idx++;
01556         idx++;
01557         cnt++;
01558     }
01559     /* ...END BAD JUJU */
01560 
01561     /* error prunning */
01562 
01563     if (literal) {
01564         FatalError("%s(%d)=> backslash escape is not "
01565                    "completed\n", file_name, file_line);
01566     }
01567     if (hexmode) {
01568         FatalError("%s(%d)=> hexmode is not "
01569                    "completed\n", file_name, file_line);
01570     }
01571 
01572     ds_idx = (PatternMatchData *) otn->ds_list[type];
01573 
01574     while(ds_idx->next != NULL)
01575         ds_idx = ds_idx->next;
01576 
01577     if((ds_idx->pattern_buf = (char *) calloc(dummy_size+1, sizeof(char))) 
01578        == NULL)
01579     {
01580         FatalError("ParsePattern() pattern_buf malloc failed!\n");
01581     }
01582 
01583     memcpy(ds_idx->pattern_buf, tmp_buf, dummy_size);
01584 
01585     ds_idx->pattern_size = dummy_size;
01586     ds_idx->search = uniSearch;
01587     
01588     make_precomp(ds_idx);
01589     ds_idx->exception_flag = exception_flag;
01590 
01591     ds_idx->pattern_max_jump_size = GetMaxJumpSize(ds_idx->pattern_buf, ds_idx->pattern_size);
01592 
01593     return;
01594 }
01595 
01596 static int CheckORPatternMatch(Packet * p, struct _OptTreeNode * otn_idx, 
01597                                OptFpList * fp_list)
01598 {
01599     int found = 0;
01600     int dsize;
01601     char *dp;
01602     
01603 
01604     PatternMatchData *idx;
01605 
01606     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "CheckPatternORMatch: "););
01607     
01608     idx = otn_idx->ds_list[PLUGIN_PATTERN_MATCH_OR];
01609 
01610     while(idx != NULL)
01611     {
01612 
01613         if((p->packet_flags & PKT_ALT_DECODE) && (idx->rawbytes == 0))
01614         {
01615             dsize = p->alt_dsize;
01616             dp = (char *) DecodeBuffer; /* decode.c */
01617             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01618                                     "Using Alternative Decode buffer!\n"););
01619         }
01620         else
01621         {
01622             dsize = p->dsize;
01623             dp = (char *) p->data;
01624         }
01625         
01626 
01627         if(idx->offset > dsize)
01628         {
01629             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01630                         "Initial offset larger than payload!\n"););
01631 
01632             goto sizetoosmall;
01633         }
01634         else
01635         {
01636             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01637                         "testing pattern: %s\n", idx->pattern_buf););
01638             found = idx->search(dp, dsize, idx);
01639 
01640             if(!found)
01641             {
01642                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01643                             "Pattern Match failed!\n"););
01644             }
01645         }
01646 
01647         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01648                     "Checking the results\n"););
01649 
01650         if(found)
01651         {
01652             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match "
01653                                     "successful: %s!\n", idx->pattern_buf););
01654 
01655             return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
01656 
01657         }
01658         else
01659         {
01660             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01661                         "Pattern match failed\n"););
01662         }
01663 
01664         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01665                     "Stepping to next content keyword\n"););
01666 
01667     sizetoosmall:
01668 
01669         idx = idx->next;
01670     }
01671 
01672     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01673                 "No more keywords, exiting... \n"););
01674 
01675     return 0;
01676 }
01677 
01678 static int CheckANDPatternMatch(Packet *p, struct _OptTreeNode *otn_idx, 
01679                                 OptFpList *fp_list)
01680 {
01681     int found = 0;
01682     int next_found;
01683     int dsize;
01684     char *dp;
01685     int origUseDoe;
01686     char *tmp_doe, *orig_doe, *start_doe;
01687 
01688     PatternMatchData *idx;
01689 
01690     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "CheckPatternANDMatch: "););
01691 
01692     idx = fp_list->context;
01693     origUseDoe = idx->use_doe;
01694 
01695     if((p->packet_flags & PKT_ALT_DECODE) && (idx->rawbytes == 0))
01696     {
01697         dsize = p->alt_dsize;
01698         dp = (char *) DecodeBuffer; /* decode.c */
01699         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01700                     "Using Alternative Decode buffer!\n"););
01701     }
01702     else
01703     {
01704         dsize = p->dsize;
01705         dp = (char *) p->data;
01706     }
01707 
01708     /* this now takes care of all the special cases where we'd run
01709      * over the buffer */
01710     orig_doe = doe_ptr;
01711     found = (idx->search(dp, dsize, idx) ^ idx->exception_flag);
01712 
01713     if (InlineMode() && found && idx->replace_buf)
01714     {
01715         //fix the packet buffer to have the new string
01716         PayloadReplace(p, otn_idx, fp_list, detect_depth);
01717     }
01718 
01719     while (found)
01720     {
01721         /* save where we last did the pattern match */
01722         tmp_doe = doe_ptr;
01723 
01724         /* save start doe as beginning of this pattern + non-repeating length*/
01725         start_doe = doe_ptr - idx->pattern_size + idx->pattern_max_jump_size;
01726 
01727         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match successful!\n"););      
01728         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Check next functions!\n"););
01729 
01730         /* Try evaluating the rest of the rules chain */
01731         next_found= fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
01732 
01733         if(next_found != 0) 
01734         {
01735             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01736                                     "Next functions matched!\n"););
01737 
01738             /* We found a successful match, return that this rule has fired off */
01739             return next_found;
01740         }
01741         else if(tmp_doe != NULL)
01742         {
01743             int new_dsize = dsize-(start_doe-dp);
01744 
01745             if(new_dsize <= 0 || new_dsize > dsize)
01746             {
01747                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01748                                         "The new dsize is less than <= 0 or > "
01749                                         "the the original dsize;returning "
01750                                         "false\n"););
01751                 idx->use_doe = origUseDoe;
01752                 return 0;
01753             }
01754             
01755             if (orig_doe)
01756             {
01757                 /* relative to a previously found pattern */
01758                 if (((idx->distance != 0) && (start_doe - orig_doe > idx->distance)) ||
01759                     ((idx->offset != 0) && (start_doe - orig_doe > idx->offset)) )
01760                 {
01761                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01762                                             "The next starting point to search "
01763                                             "from is beyond the original "
01764                                             "distance;returning false\n"););
01765                     idx->use_doe = origUseDoe;
01766                     return 0;
01767                 }
01768 
01769                 if (((idx->within != 0) &&
01770                      (start_doe - orig_doe + idx->pattern_size > (unsigned int)idx->within)) ||
01771                     ((idx->depth != 0) &&
01772                      (start_doe - orig_doe + idx->pattern_size > (unsigned int)idx->depth)) )
01773                 {
01774                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01775                                             "The next starting point to search "
01776                                             "from is beyond the original "
01777                                             "within;returning false\n"););
01778                     idx->use_doe = origUseDoe;
01779                     return 0;
01780                 }
01781             }
01782             else
01783             {
01784                 /* relative to beginning of data */
01785                 if (((idx->distance != 0) && (start_doe - dp > idx->distance)) ||
01786                     ((idx->offset != 0) && (start_doe - dp > idx->offset)) )
01787                 {
01788                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01789                                             "The next starting point to search "
01790                                             "from is beyond the original "
01791                                             "distance;returning false\n"););
01792                     idx->use_doe = origUseDoe;
01793                     return 0;
01794                 }
01795 
01796                 if (((idx->within != 0) &&
01797                      (start_doe - dp + idx->pattern_size > (unsigned int)idx->within)) ||
01798                     ((idx->depth != 0) &&
01799                      (start_doe - dp + idx->pattern_size > (unsigned int)idx->depth)) )
01800                 {
01801                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01802                                             "The next starting point to search "
01803                                             "from is beyond the original "
01804                                             "within;returning false\n"););
01805                     idx->use_doe = origUseDoe;
01806                     return 0;
01807                 }
01808             }
01809 
01810             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01811                                     "At least ONE of the next functions does to match!\n"););      
01812             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01813                                     "Start search again from a next point!\n"););
01814 
01815             /* Start the search again from the last set of contents, with a new depth and dsize */
01816             doe_ptr = start_doe;
01817             idx->use_doe = 1;
01818             found = (idx->search(start_doe, new_dsize,idx) ^ idx->exception_flag);
01819             
01820             /*
01821             **  If we haven't updated doe since we set it at the beginning
01822             **  of the loop, then that means we have already done the exact 
01823             **  same search previously, and have nothing else to gain from
01824             **  doing the same search again.
01825             */
01826             if(start_doe == (char *)doe_ptr)
01827             {
01828                 idx->use_doe = origUseDoe;
01829                 return 0;
01830             }
01831         }
01832         else
01833         {
01834             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01835                                     "Returning 0 because tmp_doe is NULL\n"););
01836             
01837             idx->use_doe = origUseDoe;
01838             return 0;
01839         }
01840             
01841     }
01842     
01843     idx->use_doe = origUseDoe;
01844     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match failed\n"););
01845     return 0;
01846 }
01847 
01848 /************************************************************************/
01849 /************************************************************************/
01850 /************************************************************************/
01851 
01852 static int CheckUriPatternMatch(Packet *p, struct _OptTreeNode *otn_idx, 
01853                                 OptFpList *fp_list)
01854 {
01855     int found = 0;
01856     int i;
01857     PatternMatchData *idx;
01858 
01859     if(p->uri_count <= 0)
01860     {
01861         DEBUG_WRAP(DebugMessage(DEBUG_HTTP_DECODE,
01862                     "CheckUriPatternMatch: p->uri_count is %d. Returning",
01863                     p->uri_count););
01864         return 0;
01865     }
01866 
01867     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "CheckUriPatternMatch: "););
01868 
01869     idx = fp_list->context;
01870 
01871     for(i=0;i < p->uri_count; i++)
01872     {
01873 
01874 #ifdef DEBUG /* for variable declaration */
01875         int j;
01876 
01877         DebugMessage(DEBUG_HTTP_DECODE,"Checking against URL: ");
01878         for(j=0; j<=UriBufs[i].length; j++)
01879         {
01880             DebugMessage(DEBUG_HTTP_DECODE, "%c", UriBufs[i].uri[j]);
01881         }
01882         DebugMessage(DEBUG_HTTP_DECODE,"\n");
01883 
01884 #endif /* DEBUG */
01885 
01886         /* 
01887          * have to reset the doe_ptr for each new UriBuf 
01888          */
01889         doe_ptr = NULL;
01890 
01891         /* this now takes care of all the special cases where we'd run
01892          * over the buffer */
01893         found = (idx->search(UriBufs[i].uri, UriBufs[i].length, idx) ^ idx->exception_flag);
01894         
01895         if(found)
01896         {
01897             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match successful!\n"););
01898             /* call the next function in the OTN */
01899             return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);        
01900         }
01901     }
01902 
01903     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match failed\n"););
01904 
01905     return 0;
01906 }
01907 
01908 
01909 
01910 /****************************************************************************
01911  *
01912  * Function: ParseContentListFile(char *, OptTreeNode *, int protocol)
01913  *
01914  * Purpose:  Read the content_list file a line at a time, put the content of
01915  *           the line into buffer
01916  *
01917  * Arguments:otn => rule including the list
01918  *           file => list file filename
01919  *           protocol => protocol
01920  *
01921  * Returns: void function
01922  *
01923  ***************************************************************************/
01924 static void ParseContentListFile(char *file, OptTreeNode * otn, int protocol)
01925 {
01926     FILE *thefp;                /* file pointer for the content_list file */
01927     char buf[STD_BUF+1];        /* file read buffer */
01928     char rule_buf[STD_BUF+1];   /* content keyword buffer */
01929     int frazes_count;           /* frazes counter */
01930 
01931 
01932 #ifdef DEBUG
01933     PatternMatchData *idx;
01934     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Opening content_list file: %s\n", file););
01935 #endif /* DEBUG */
01936     /* open the list file */
01937     if((thefp = fopen(file, "r")) == NULL)
01938     {
01939         FatalError("Unable to open list file: %s\n", file);
01940     }
01941     /* clear the line and rule buffers */
01942     bzero((char *) buf, STD_BUF);
01943     bzero((char *) rule_buf, STD_BUF);
01944     frazes_count = 0;
01945 
01946     /* loop thru each list_file line and content to the rule */
01947     while((fgets(buf, STD_BUF-2, thefp)) != NULL)
01948     {
01949         /* inc the line counter */
01950         list_file_line++;
01951 
01952         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Got line %d: %s", 
01953                                 list_file_line, buf););
01954 
01955         /* if it's not a comment or a <CR>, send it to the parser */
01956         if((buf[0] != '#') && (buf[0] != 0x0a) && (buf[0] != ';'))
01957         {
01958             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
01959                                     "Adding content keyword: %s", buf););
01960 
01961             frazes_count++;
01962             strip(buf);
01963 
01964             NewNode(otn, PLUGIN_PATTERN_MATCH_OR);
01965 
01966             /* check and add content keyword */
01967             ParsePattern(buf, otn, PLUGIN_PATTERN_MATCH_OR);
01968 
01969             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
01970                         "Content keyword %s\" added!\n", buf););
01971         }
01972     }
01973 #ifdef DEBUG
01974     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "%d frazes read...\n", frazes_count););
01975     idx = (PatternMatchData *) otn->ds_list[PLUGIN_PATTERN_MATCH_OR];
01976     
01977     if(idx == NULL)
01978     {
01979         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "No patterns loaded\n"););
01980     }
01981     else
01982     {
01983         while(idx != NULL)
01984         {
01985             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern = %s\n", 
01986                                     idx->pattern_buf););
01987             idx = idx->next;
01988         }
01989     }
01990 #endif /* DEBUG */
01991     
01992     fclose(thefp);
01993 
01994     return;
01995 }

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