00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025
00026 #include "bounds.h"
00027 #include "rules.h"
00028 #include "debug.h"
00029 #include "decode.h"
00030 #include "plugbase.h"
00031 #include "parser.h"
00032 #include "plugin_enum.h"
00033 #include "util.h"
00034 #include "mstring.h"
00035 #include <sys/types.h>
00036
00037 #ifdef WIN32
00038 #define PCRE_DEFINITION
00039 #endif
00040
00041 #include <pcre.h>
00042
00043 typedef struct _PcreData
00044 {
00045 pcre *re;
00046 pcre_extra *pe;
00047 int options;
00048 } PcreData;
00049
00050
00051 #define SNORT_PCRE_RELATIVE 1
00052 #define SNORT_PCRE_INVERT 2
00053 #define SNORT_PCRE_URI 4
00054 #define SNORT_PCRE_RAWBYTES 8
00055
00056
00057
00058
00059
00060
00061
00062 #define SNORT_PCRE_OVECTOR_SIZE 3
00063
00064 extern u_int8_t DecodeBuffer[DECODE_BLEN];
00065 extern u_int8_t *doe_ptr;
00066
00067 void SnortPcreInit(char *, OptTreeNode *, int);
00068 void SnortPcreParse(char *, PcreData *, OptTreeNode *);
00069 void SnortPcreDump(PcreData *);
00070 int SnortPcre(Packet *, struct _OptTreeNode *, OptFpList *);
00071
00072 void SetupPcre(void)
00073 {
00074 RegisterPlugin("pcre", SnortPcreInit);
00075 }
00076
00077 void SnortPcreInit(char *data, OptTreeNode *otn, int protocol)
00078 {
00079 PcreData *pcre_data;
00080 OptFpList *fpl;
00081
00082
00083
00084
00085 pcre_data = (PcreData *) SnortAlloc(sizeof(PcreData));
00086
00087 if(pcre_data == NULL)
00088 {
00089 FatalError("%s (%d): Unable to allocate pcre_data node\n",
00090 file_name, file_line);
00091 }
00092
00093 SnortPcreParse(data, pcre_data, otn);
00094
00095 fpl = AddOptFuncToList(SnortPcre, otn);
00096
00097
00098
00099
00100
00101 fpl->context = (void *) pcre_data;
00102
00103 return;
00104 }
00105
00106 void SnortPcreParse(char *data, PcreData *pcre_data, OptTreeNode *otn)
00107 {
00108 const char *error;
00109 char *re, *free_me;
00110 char *opts;
00111 char delimit = '/';
00112 int erroffset;
00113 int compile_flags = 0;
00114
00115 if(data == NULL)
00116 {
00117 FatalError("%s (%d): pcre requires a regular expression\n",
00118 file_name, file_line);
00119 }
00120
00121 if(!(free_me = strdup(data)))
00122 {
00123 FatalError("%s (%d): pcre strdup() failed\n", file_name, file_line);
00124 }
00125 re = free_me;
00126
00127
00128
00129 while (isspace((int)re[strlen(re)-1])) re[strlen(re)-1] = '\0';
00130 while (isspace((int)*re)) re++;
00131
00132 if(*re == '!') {
00133 pcre_data->options |= SNORT_PCRE_INVERT;
00134 re++;
00135 while(isspace((int)*re)) re++;
00136 }
00137
00138
00139 if(*re != '"') {
00140 printf("It isn't \"\n");
00141 goto syntax;
00142 }
00143 re++;
00144
00145 if(re[strlen(re)-1] != '"')
00146 {
00147 printf("It isn't \"\n");
00148 goto syntax;
00149 }
00150
00151
00152 re[strlen(re) - 1] = '\0';
00153
00154
00155
00156 if(*re == 'm')
00157 {
00158 re++;
00159 if(! *re) goto syntax;
00160
00161
00162 if(isspace((int)*re)) goto syntax;
00163
00164 if(*re == 'R') goto syntax;
00165
00166 delimit = *re;
00167 }
00168 else if(! *re == delimit)
00169 goto syntax;
00170
00171
00172 opts = strrchr(re, delimit);
00173 if(!((opts - re) > 1))
00174 goto syntax;
00175
00176 re++;
00177 *opts++ = '\0';
00178
00179
00180 while(*opts != '\0') {
00181 switch(*opts) {
00182 case 'i': compile_flags |= PCRE_CASELESS; break;
00183 case 's': compile_flags |= PCRE_DOTALL; break;
00184 case 'm': compile_flags |= PCRE_MULTILINE; break;
00185 case 'x': compile_flags |= PCRE_EXTENDED; break;
00186
00187
00188
00189
00190 case 'A': compile_flags |= PCRE_ANCHORED; break;
00191 case 'E': compile_flags |= PCRE_DOLLAR_ENDONLY; break;
00192 case 'G': compile_flags |= PCRE_UNGREEDY; break;
00193
00194
00195
00196
00197 case 'R': pcre_data->options |= SNORT_PCRE_RELATIVE; break;
00198 case 'U': pcre_data->options |= SNORT_PCRE_URI; break;
00199 case 'B': pcre_data->options |= SNORT_PCRE_RAWBYTES; break;
00200 default:
00201 FatalError("%s (%d): unknown/extra pcre option encountered\n", file_name, file_line);
00202 }
00203 opts++;
00204 }
00205
00206 if(pcre_data->options & SNORT_PCRE_RELATIVE &&
00207 pcre_data->options & SNORT_PCRE_URI)
00208 FatalError("%s(%d): PCRE unsupported configuration : both relative & uri options specified\n", file_name, file_line);
00209
00210
00211
00212 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre: compiling %s\n", re););
00213 pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, NULL);
00214
00215 if(pcre_data->re == NULL)
00216 {
00217 FatalError("%s(%d) : pcre compile of \"%s\" failed at offset "
00218 "%d : %s\n", file_name, file_line, re, erroffset, error);
00219 }
00220
00221
00222
00223 pcre_data->pe = pcre_study(pcre_data->re, 0, &error);
00224
00225 if(error != NULL)
00226 {
00227 FatalError("%s(%d) : pcre study failed : %s\n", file_name,
00228 file_line, error);
00229 }
00230
00231 free(free_me);
00232
00233 return;
00234
00235 syntax:
00236 if(free_me) free(free_me);
00237
00238 FatalError("ERROR %s Line %d => unable to parse pcre regex %s\n",
00239 file_name, file_line, data);
00240
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 static int pcre_search(const PcreData *pcre_data,
00257 const char *buf,
00258 int len,
00259 int start_offset,
00260 int *found_offset)
00261 {
00262 int ovector[SNORT_PCRE_OVECTOR_SIZE];
00263 int matched;
00264 int result;
00265
00266 if(pcre_data == NULL
00267 || buf == NULL
00268 || len <= 0
00269 || start_offset < 0
00270 || start_offset >= len
00271 || found_offset == NULL)
00272 {
00273 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00274 "Returning 0 because we didn't have the required parameters!\n"););
00275 return 0;
00276 }
00277
00278 *found_offset = -1;
00279
00280 result = pcre_exec(pcre_data->re,
00281 pcre_data->pe,
00282 buf,
00283 len,
00284 start_offset,
00285 0,
00286 ovector,
00287 SNORT_PCRE_OVECTOR_SIZE);
00288
00289 if(result >= 0)
00290 {
00291 matched = 1;
00292 }
00293 else if(result == PCRE_ERROR_NOMATCH)
00294 {
00295 matched = 0;
00296 }
00297 else
00298 {
00299 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result););
00300 return 0;
00301 }
00302
00303
00304 if(pcre_data->options & SNORT_PCRE_INVERT)
00305 {
00306 matched = !matched;
00307 }
00308 else
00309 {
00310
00311 *found_offset = ovector[1];
00312 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00313 "Setting Doe_ptr and found_offset: %p %d\n",
00314 doe_ptr, found_offset););
00315 }
00316
00317 return matched;
00318 }
00319
00320 int SnortPcre(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00321 {
00322 PcreData *pcre_data;
00323 int found_offset;
00324 char *base_ptr, *end_ptr, *start_ptr;
00325 int dsize;
00326 int length;
00327 int matched = 0;
00328 extern HttpUri UriBufs[URI_COUNT];
00329 int i;
00330
00331 DEBUG_WRAP(char *hexbuf;);
00332
00333
00334 pcre_data =(PcreData *) fp_list->context;
00335
00336
00337 if(pcre_data->options & SNORT_PCRE_URI)
00338 {
00339 for(i=0;i<p->uri_count;i++)
00340 {
00341 matched = pcre_search(pcre_data,
00342 UriBufs[i].uri,
00343 UriBufs[i].length,
00344 0,
00345 &found_offset);
00346
00347 if(matched)
00348 {
00349
00350 return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00351 }
00352 }
00353
00354 return 0;
00355 }
00356
00357
00358 if(p->packet_flags & PKT_ALT_DECODE && !(pcre_data->options & SNORT_PCRE_RAWBYTES))
00359 {
00360 dsize = p->alt_dsize;
00361 start_ptr = (char *) DecodeBuffer;
00362 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00363 "using alternative decode buffer in pcre!\n"););
00364 }
00365 else
00366 {
00367 dsize = p->dsize;
00368 start_ptr = (char *) p->data;
00369 }
00370
00371 base_ptr = start_ptr;
00372 end_ptr = start_ptr + dsize;
00373
00374
00375 if(pcre_data->options & SNORT_PCRE_RELATIVE && doe_ptr)
00376 {
00377 if(!inBounds(start_ptr, end_ptr, doe_ptr))
00378 {
00379 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00380 "pcre bounds check failed on a relative content match\n"););
00381 return 0;
00382 }
00383
00384 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00385 "pcre ... checking relative offset\n"););
00386 base_ptr = doe_ptr;
00387 }
00388 else
00389 {
00390 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00391 "pcre ... checking absolute offset\n"););
00392 base_ptr = start_ptr;
00393 }
00394
00395 length = end_ptr - base_ptr;
00396
00397 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00398 "pcre ... base: %p start: %p end: %p doe: %p length: %d\n",
00399 base_ptr, start_ptr, end_ptr, doe_ptr, length););
00400
00401 DEBUG_WRAP(hexbuf = hex(base_ptr, length);
00402 DebugMessage(DEBUG_PATTERN_MATCH, "pcre payload: %s\n", hexbuf);
00403 free(hexbuf);
00404 );
00405
00406
00407 matched = pcre_search(pcre_data, base_ptr, length, 0, &found_offset);
00408
00409
00410 if(found_offset > 0)
00411 {
00412 doe_ptr = (u_int8_t *) base_ptr + found_offset;
00413 }
00414
00415 while(matched)
00416 {
00417 int search_offset = found_offset;
00418 int next_found = fp_list->next->OptTestFunc(p, otn, fp_list->next);
00419
00420 if(next_found)
00421 {
00422
00423
00424
00425
00426 doe_ptr = (u_int8_t *) base_ptr + found_offset;
00427
00428 return 1;
00429 }
00430
00431
00432 if(search_offset <= 0 || length < search_offset)
00433 {
00434
00435 return 0;
00436 }
00437
00438 matched = pcre_search(pcre_data, base_ptr, length,
00439 search_offset, &found_offset);
00440
00441
00442 if(found_offset > 0)
00443 {
00444 doe_ptr = (u_int8_t *) base_ptr + found_offset;
00445 }
00446
00447 if(matched)
00448 {
00449 if(fp_list->next->OptTestFunc(p, otn, fp_list->next))
00450 {
00451
00452
00453
00454 return 1;
00455 }
00456
00457 }
00458 }
00459
00460
00461 return 0;
00462 }
00463