Azinix

rlpUtil.c

Go to the documentation of this file.
00001 /** \file rlpUtil.c
00002 
00003 \brief Routines for manipulating rules
00004 
00005 ******************************************************************************/
00006 
00007 #include "rlp.h"
00008 
00009 /**AutomaticStart*************************************************************/
00010 
00011 /*---------------------------------------------------------------------------*/
00012 /* Static function prototypes                                                */
00013 /*---------------------------------------------------------------------------*/
00014 
00015 static void setEntryType (Rlp_Formula_t * entry, char *attribute);
00016 static int parseRawValue (Rlp_Formula_t * entry);
00017 static int parseByteJump (Rlp_Formula_t * entry);
00018 static int parseByteTest (Rlp_Formula_t * entry);
00019 static int parseIpProto (Rlp_Formula_t * entry);
00020 static int parseDsize (Rlp_Formula_t * entry);
00021 static int parseSample (Rlp_Formula_t * entry);
00022 static int parseInterface (Rlp_Formula_t * entry);
00023 static int parseTtl (Rlp_Formula_t * entry);
00024 static int parseIpOpts (Rlp_Formula_t * entry);
00025 static int parseFragbits (Rlp_Formula_t * entry);
00026 static int parseFlags (Rlp_Formula_t * entry);
00027 static Rlp_FlagType_t parseIndividualFlag (char *rawValue, char flag);
00028 static int parseRpc (Rlp_Formula_t * entry);
00029 static int parseContent (Rlp_Formula_t * entry);
00030 static int hexToInt (char hexChar);
00031 static int parseUricontent (Rlp_Formula_t * entry);
00032 static bool isComment (char *attribute);
00033 static int parsePcre (Rlp_Formula_t * entry);
00034 
00035 /**AutomaticEnd***************************************************************/
00036 
00037 /**
00038   * \brief  Convert a rule parse tree to a formula text string.
00039   * 
00040   */
00041 
00042 char *
00043 Rlp_ConvertParseTreeToText (Rlp_Formula_t * aFormula)
00044 {
00045   char tmpString[5000];
00046   char *text;
00047 
00048   if (aFormula == NIL (Rlp_Formula_t))
00049     {
00050       return util_strsav ("");
00051     }
00052 
00053   switch (aFormula->type)
00054     {
00055 
00056     case Rlp_Undef_c:
00057       return (util_strsav ("-UNDEF-"));
00058       break;
00059 
00060     case Rlp_Ack_c:
00061       sprintf (tmpString, "ack: ");
00062       text =
00063     util_strcat (tmpString,
00064              Rlp_ConvertParseTreeToText (aFormula->lchild));
00065       return text;
00066       break;
00067 
00068     case Rlp_Byte_Jump_c:
00069       sprintf (tmpString, "( byte_jump: ");
00070       text =
00071     util_strcat3 (tmpString,
00072               Rlp_ConvertParseTreeToText (aFormula->lchild), ")");
00073       return text;
00074     case Rlp_Byte_Test_c:
00075       sprintf (tmpString, "byte_test: ");
00076       text =
00077     util_strcat (tmpString,
00078              Rlp_ConvertParseTreeToText (aFormula->lchild));
00079       return text;
00080       break;
00081 
00082     case Rlp_Content_c:
00083       sprintf (tmpString, "content: ");
00084       text =
00085     util_strcat (tmpString,
00086              Rlp_ConvertParseTreeToText (aFormula->lchild));
00087       return text;
00088       break;
00089 
00090     case Rlp_Depth_c:
00091       sprintf (tmpString, "depth: ");
00092       text =
00093     util_strcat (tmpString,
00094              Rlp_ConvertParseTreeToText (aFormula->lchild));
00095       return text;
00096       break;
00097 
00098     case Rlp_Distance_c:
00099       sprintf (tmpString, "distance: ");
00100       text =
00101     util_strcat (tmpString,
00102              Rlp_ConvertParseTreeToText (aFormula->lchild));
00103       return text;
00104       break;
00105 
00106     case Rlp_Dsize_c:
00107       sprintf (tmpString, "dsize: ");
00108       text =
00109     util_strcat (tmpString,
00110              Rlp_ConvertParseTreeToText (aFormula->lchild));
00111       return text;
00112       break;
00113 
00114     case Rlp_Flags_c:
00115       sprintf (tmpString, "flags: ");
00116       text =
00117     util_strcat (tmpString,
00118              Rlp_ConvertParseTreeToText (aFormula->lchild));
00119       return text;
00120       break;
00121 
00122     case Rlp_Fragbits_c:
00123       sprintf (tmpString, "fragbits: ");
00124       text =
00125     util_strcat (tmpString,
00126              Rlp_ConvertParseTreeToText (aFormula->lchild));
00127       return text;
00128       break;
00129 
00130     case Rlp_Icmp_Id_c:
00131       sprintf (tmpString, "icmp_id: ");
00132       text =
00133     util_strcat (tmpString,
00134              Rlp_ConvertParseTreeToText (aFormula->lchild));
00135       return text;
00136       break;
00137 
00138     case Rlp_Icmp_Seq_c:
00139       sprintf (tmpString, "icmp_seq: ");
00140       text =
00141     util_strcat (tmpString,
00142              Rlp_ConvertParseTreeToText (aFormula->lchild));
00143       return text;
00144       break;
00145 
00146     case Rlp_Icode_c:
00147       sprintf (tmpString, "icode: ");
00148       text =
00149     util_strcat (tmpString,
00150              Rlp_ConvertParseTreeToText (aFormula->lchild));
00151       return text;
00152       break;
00153 
00154     case Rlp_Id_c:
00155       sprintf (tmpString, "id: ");
00156       text =
00157     util_strcat (tmpString,
00158              Rlp_ConvertParseTreeToText (aFormula->lchild));
00159       return text;
00160       break;
00161 
00162     case Rlp_Ip_Proto_c:
00163       sprintf (tmpString, "proto: ");
00164       text =
00165     util_strcat (tmpString,
00166              Rlp_ConvertParseTreeToText (aFormula->lchild));
00167       return text;
00168       break;
00169 
00170     case Rlp_IpOpts_c:
00171       sprintf (tmpString, "ipopts: ");
00172       text =
00173     util_strcat (tmpString,
00174              Rlp_ConvertParseTreeToText (aFormula->lchild));
00175       return text;
00176       break;
00177 
00178     case Rlp_Itype_c:
00179       sprintf (tmpString, "itype: ");
00180       text =
00181     util_strcat (tmpString,
00182              Rlp_ConvertParseTreeToText (aFormula->lchild));
00183       return text;
00184       break;
00185 
00186     case Rlp_Nocase_c:
00187       sprintf (tmpString, "case: ");
00188       text =
00189     util_strcat (tmpString,
00190              Rlp_ConvertParseTreeToText (aFormula->lchild));
00191       return text;
00192       break;
00193 
00194     case Rlp_Offset_c:
00195       sprintf (tmpString, "offset: ");
00196       text =
00197     util_strcat (tmpString,
00198              Rlp_ConvertParseTreeToText (aFormula->lchild));
00199       return text;
00200       break;
00201 
00202     case Rlp_Pcre_c:
00203       sprintf (tmpString, "pcre: ");
00204       text =
00205     util_strcat (tmpString,
00206              Rlp_ConvertParseTreeToText (aFormula->lchild));
00207       return text;
00208       break;
00209 
00210     case Rlp_Rpc_c:
00211       sprintf (tmpString, "rpc: ");
00212       text =
00213     util_strcat (tmpString,
00214              Rlp_ConvertParseTreeToText (aFormula->lchild));
00215       return text;
00216       break;
00217 
00218     case Rlp_Sameip_c:
00219       sprintf (tmpString, "sameip: ");
00220       text =
00221     util_strcat (tmpString,
00222              Rlp_ConvertParseTreeToText (aFormula->lchild));
00223       return text;
00224       break;
00225 
00226     case Rlp_Seq_c:
00227       sprintf (tmpString, "seq: ");
00228       text =
00229     util_strcat (tmpString,
00230              Rlp_ConvertParseTreeToText (aFormula->lchild));
00231       return text;
00232       break;
00233 
00234     case Rlp_Ttl_c:
00235       sprintf (tmpString, "ttl: ");
00236       text =
00237     util_strcat (tmpString,
00238              Rlp_ConvertParseTreeToText (aFormula->lchild));
00239       return text;
00240       break;
00241 
00242     case Rlp_Uricontent_c:
00243       sprintf (tmpString, "uricontent: ");
00244       text =
00245     util_strcat (tmpString,
00246              Rlp_ConvertParseTreeToText (aFormula->lchild));
00247       return text;
00248       break;
00249 
00250     case Rlp_Within_c:
00251       sprintf (tmpString, "within: ");
00252       text =
00253     util_strcat (tmpString,
00254              Rlp_ConvertParseTreeToText (aFormula->lchild));
00255       return text;
00256       break;
00257 
00258     case Rlp_Ip_c:
00259       return util_strsav (" ( ip ) ");
00260 
00261     case Rlp_Tcp_c:
00262       return util_strsav (" ( tcp ) ");
00263 
00264     case Rlp_Udp_c:
00265       return util_strsav (" ( udp ) ");
00266 
00267     case Rlp_Icmp_c:
00268       return util_strsav (" ( icmp ) ");
00269 
00270     case Rlp_IpBlock_c:
00271       return util_strcat5 (" ( ip ",
00272                Rlp_ConvertParseTreeToText (aFormula->lchild),
00273                " / ",
00274                Rlp_ConvertParseTreeToText (aFormula->rchild),
00275                " ) ");
00276 
00277     case Rlp_Num_c:
00278       printf ("Calling Rlp_Num_c:\n");
00279       sprintf (tmpString, "%d", (int) aFormula->lchild);
00280       return (util_strsav (tmpString));
00281 
00282     case Rlp_Text_c:
00283       sprintf (tmpString, "%s", (char *) aFormula->lchild);
00284       return (util_strsav (tmpString));
00285 
00286     case Rlp_PortUnion_c:
00287       return (util_strcat3 (Rlp_ConvertParseTreeToText (aFormula->lchild),
00288                 ",",
00289                 Rlp_ConvertParseTreeToText (aFormula->rchild)));
00290 
00291     case Rlp_IpUnion_c:
00292       return (util_strcat5 ("(",
00293                 Rlp_ConvertParseTreeToText (aFormula->lchild),
00294                 ",",
00295                 Rlp_ConvertParseTreeToText (aFormula->rchild),
00296                 ")"));
00297 
00298     case Rlp_Negation_c:
00299       sprintf (tmpString, "!%s",
00300            Rlp_ConvertParseTreeToText (aFormula->lchild));
00301       return (util_strsav (tmpString));
00302 
00303 
00304     case Rlp_PortRange_c:
00305       return (util_strcat5
00306           ("(", Rlp_ConvertParseTreeToText (aFormula->lchild), ":",
00307            Rlp_ConvertParseTreeToText (aFormula->rchild), ")"));
00308 
00309     case Rlp_List_c:
00310       return (util_strcat3 (Rlp_ConvertParseTreeToText (aFormula->lchild),
00311                 " ",
00312                 Rlp_ConvertParseTreeToText (aFormula->rchild)));
00313 
00314     default:
00315       printf ("Panic: no type\n");
00316       return util_strsav ("-UNRECOG TYPE-");
00317       break;
00318 
00319     }               // switch
00320 
00321   Rlp_PrintFormulaTree (aFormula->lchild);
00322   Rlp_PrintFormulaTree (aFormula->rchild);
00323 
00324   return 0;
00325 
00326 }
00327 
00328 
00329 /**
00330   * \brief  Print a rule parse tree.
00331   * 
00332   */
00333 
00334 int
00335 Rlp_PrintFormulaTree (Rlp_Formula_t * aFormula)
00336 {
00337   if (aFormula == NIL (Rlp_Formula_t))
00338     {
00339       printf ("NODE: %p --- Nil\n", aFormula);
00340       return 0;
00341     }
00342 
00343   switch (aFormula->type)
00344     {
00345 
00346     case Rlp_Undef_c:
00347       printf ("NODE: %p --- Rlp_Undef_c:\n", aFormula);
00348       break;
00349     case Rlp_Ack_c:
00350       printf ("NODE: %p --- Rlp_Ack_c\n", aFormula);
00351       break;
00352     case Rlp_Byte_Jump_c:
00353       printf ("NODE: %p --- Rlp_Byte_Jump_c\n", aFormula);
00354       break;
00355     case Rlp_Byte_Test_c:
00356       printf ("NODE: %p --- Rlp_Byte_Test_c\n", aFormula);
00357       break;
00358     case Rlp_Content_c:
00359       printf ("NODE: %p --- Rlp_Content_c\n", aFormula);
00360       break;
00361     case Rlp_Depth_c:
00362       printf ("NODE: %p --- Rlp_Depth_c\n", aFormula);
00363       break;
00364     case Rlp_Distance_c:
00365       printf ("NODE: %p --- Rlp_Distance_c\n", aFormula);
00366       break;
00367     case Rlp_Dsize_c:
00368       printf ("NODE: %p --- Rlp_Dsize_c\n", aFormula);
00369       break;
00370     case Rlp_Flags_c:
00371       printf ("NODE: %p --- Rlp_Flags_c\n", aFormula);
00372       break;
00373     case Rlp_Fragbits_c:
00374       printf ("NODE: %p --- Rlp_Fragbits_c\n", aFormula);
00375       break;
00376     case Rlp_Icmp_Id_c:
00377       printf ("NODE: %p --- Rlp_Icmp_Id_c\n", aFormula);
00378       break;
00379     case Rlp_Icmp_Seq_c:
00380       printf ("NODE: %p --- Rlp_Icmp_Seq_c\n", aFormula);
00381       break;
00382     case Rlp_Icode_c:
00383       printf ("NODE: %p --- Rlp_Icode_c\n", aFormula);
00384       break;
00385     case Rlp_Id_c:
00386       printf ("NODE: %p --- Rlp_Id_c\n", aFormula);
00387       break;
00388     case Rlp_Ip_Proto_c:
00389       printf ("NODE: %p --- Rlp_Ip_Proto_c\n", aFormula);
00390       break;
00391     case Rlp_IpOpts_c:
00392       printf ("NODE: %p --- Rlp_IpOpts_c\n", aFormula);
00393       break;
00394     case Rlp_Itype_c:
00395       printf ("NODE: %p --- Rlp_Itype_c\n", aFormula);
00396       break;
00397     case Rlp_Nocase_c:
00398       printf ("NODE: %p --- Rlp_Nocase_c\n", aFormula);
00399       break;
00400     case Rlp_Offset_c:
00401       printf ("NODE: %p --- Rlp_Offset_c\n", aFormula);
00402       break;
00403     case Rlp_Rpc_c:
00404       printf ("NODE: %p --- Rlp_Rpc_c\n", aFormula);
00405       break;
00406     case Rlp_Sameip_c:
00407       printf ("NODE: %p --- Rlp_Sameip_c\n", aFormula);
00408       break;
00409     case Rlp_Seq_c:
00410       printf ("NODE: %p --- Rlp_Seq_c\n", aFormula);
00411       break;
00412     case Rlp_Ttl_c:
00413       printf ("NODE: %p --- Rlp_Ttl_c\n", aFormula);
00414       break;
00415     case Rlp_Uricontent_c:
00416       printf ("NODE: %p --- Rlp_Uricontent_c\n", aFormula);
00417       break;
00418     case Rlp_Within_c:
00419       printf ("NODE: %p --- Rlp_Within_c\n", aFormula);
00420       break;
00421     case Rlp_Tcp_c:
00422       printf ("NODE: %p --- Rlp_Tcp_c\n", aFormula);
00423       break;
00424     case Rlp_Udp_c:
00425       printf ("NODE: %p --- Rlp_Udp_c\n", aFormula);
00426       break;
00427     case Rlp_Icmp_c:
00428       printf ("NODE: %p --- Rlp_Icmp_c\n", aFormula);
00429       break;
00430     case Rlp_Ip_c:
00431       printf ("NODE: %p --- Rlp_Ip_c\n", aFormula);
00432       break;
00433     case Rlp_IpBlock_c:
00434       printf ("NODE: %p --- Rlp_IpBlock_c\n", aFormula);
00435       break;
00436     case Rlp_Num_c:
00437       printf ("NODE: %p --- Rlp_Num_c, value = %d\n", aFormula,
00438           (int) aFormula->lchild);
00439       return 0;
00440     case Rlp_Text_c:
00441       printf ("NODE: %p --- Rlp_Text_c, value = %s\n", aFormula,
00442           (char *) aFormula->lchild);
00443       return 0;
00444     case Rlp_PortUnion_c:
00445       printf ("NODE: %p --- Rlp_PortUnion_c\n", aFormula);
00446       break;
00447     case Rlp_IpUnion_c:
00448       printf ("NODE: %p --- Rlp_IpUnion_c\n", aFormula);
00449       break;
00450     case Rlp_Negation_c:
00451       printf ("NODE: %p --- Rlp_Negation_c\n", aFormula);
00452       break;
00453     case Rlp_PortRange_c:
00454       printf ("NODE: %p --- Rlp_PortRange_c\n", aFormula);
00455       break;
00456     case Rlp_List_c:
00457       printf ("NODE: %p --- Rlp_List_c\n", aFormula);
00458       break;
00459     default:
00460       printf ("Panic: no type\n");
00461       return -1;
00462 
00463     }               // switch
00464 
00465   Rlp_PrintFormulaTree (aFormula->lchild);
00466   Rlp_PrintFormulaTree (aFormula->rchild);
00467 
00468   return 0;
00469 
00470 }
00471 
00472 
00473 /**
00474   * \brief  Free a parse tree
00475   * 
00476   */
00477 
00478 void
00479 Rlp_FormulaFree (Rlp_Formula_t * aFormula)
00480 {
00481   if (aFormula == NIL (Rlp_Formula_t))
00482     {
00483       return;
00484     }
00485 
00486   switch (aFormula->type)
00487     {
00488 
00489     case Rlp_Undef_c:
00490     case Rlp_Ack_c:
00491     case Rlp_Byte_Jump_c:
00492     case Rlp_Byte_Test_c:
00493     case Rlp_Content_c:
00494     case Rlp_Depth_c:
00495     case Rlp_Distance_c:
00496     case Rlp_Dsize_c:
00497     case Rlp_Flags_c:
00498     case Rlp_Fragbits_c:
00499     case Rlp_Icmp_Id_c:
00500     case Rlp_Icmp_Seq_c:
00501     case Rlp_Icode_c:
00502     case Rlp_Id_c:
00503     case Rlp_Ip_Proto_c:
00504     case Rlp_IpOpts_c:
00505     case Rlp_Itype_c:
00506     case Rlp_Nocase_c:
00507     case Rlp_Offset_c:
00508     case Rlp_Rpc_c:
00509     case Rlp_Sameip_c:
00510     case Rlp_Seq_c:
00511     case Rlp_Ttl_c:
00512     case Rlp_Uricontent_c:
00513     case Rlp_Within_c:
00514     case Rlp_Ip_c:
00515     case Rlp_Tcp_c:
00516     case Rlp_Udp_c:
00517     case Rlp_Icmp_c:
00518     case Rlp_IpBlock_c:
00519     case Rlp_PortUnion_c:
00520     case Rlp_IpUnion_c:
00521     case Rlp_Negation_c:
00522     case Rlp_PortRange_c:
00523     case Rlp_List_c:
00524       Rlp_FormulaFree (aFormula->lchild);
00525       Rlp_FormulaFree (aFormula->rchild);
00526       free (aFormula);
00527       return;
00528 
00529     case Rlp_Num_c:
00530       free (aFormula);      // can't recur since lchild is an int
00531       return;
00532 
00533     case Rlp_Text_c:
00534       free (aFormula->lchild);  // free the text stored here first
00535       free (aFormula);
00536       return;
00537 
00538     default:
00539       printf ("Panic: no type\n");
00540       return;
00541 
00542     }               // switch
00543 
00544 }
00545 
00546 
00547 /**
00548   * \brief  Create a parse tree for an L7 formula from raw text of formula
00549   * 
00550   */
00551 
00552 Rlp_Formula_t *
00553 Rlp_CreateParseTreeFromText (char *text)
00554 {
00555   // this is done in two stages - Rlp_L7StringParse 
00556   // tokenizes the input rule into attrib value pairs (char *)
00557   // then Rlp_CreateParseTreeFromAttribValuePairArray parses the attrib-value pairs
00558   array_t *attribValueArray = Rlp_L7StringParse (text);
00559   Rlp_Formula_t *L7Formula =
00560     Rlp_CreateParseTreeFromAttribValuePairArray (attribValueArray);
00561   Rlp_FreeArrayOfStrings (attribValueArray);
00562 
00563   return L7Formula;
00564 }
00565 
00566 
00567 /** \brief  Create a parse tree from a L7 formula that is presented
00568   as an array of (attribute,value) pairs.
00569   
00570 Returns NIL if the array is of length 0, otherwise list has as many
00571 entries as the array has members.
00572 */
00573 
00574 Rlp_Formula_t *
00575 Rlp_CreateParseTreeFromAttribValuePairArray (array_t * aRule)
00576 {
00577   if (array_n (aRule) == 0)
00578     {
00579       return NIL (Rlp_Formula_t);
00580     }
00581 
00582   Rlp_Formula_t *listNode;
00583   Rlp_Formula_t *nextNode;
00584   array_t *listNodeArray = array_alloc (Rlp_Formula_t *, 0);
00585 
00586   int i;
00587   for (i = 0; i < array_n (aRule); i++)
00588     {
00589 
00590       Rlp_RuleComponent_t *aComponent =
00591     array_fetch (Rlp_RuleComponent_t *, aRule, i);
00592 
00593       if (isComment (aComponent->rawAttribute))
00594     {
00595       continue;
00596     }
00597 
00598       Rlp_Formula_t *entry =
00599     new_node (Rlp_Undef_c, NIL (Rlp_Formula_t), NIL (Rlp_Formula_t));
00600       setEntryType (entry, aComponent->rawAttribute);
00601       entry->lchild = (Rlp_Formula_t *) aComponent->rawValue;
00602       parseRawValue (entry);
00603 
00604       listNode = new_node (Rlp_List_c, entry, NIL (Rlp_Formula_t));
00605       array_insert_last (Rlp_Formula_t *, listNodeArray, listNode);
00606     }
00607 
00608   if (array_n (listNodeArray) > 0)
00609     {
00610       for (i = 0; i < array_n (listNodeArray) - 1; i++)
00611     {
00612       listNode = array_fetch (Rlp_Formula_t *, listNodeArray, i);
00613       nextNode = array_fetch (Rlp_Formula_t *, listNodeArray, i + 1);
00614       listNode->rchild = nextNode;
00615     }
00616       Rlp_Formula_t *result = array_fetch (Rlp_Formula_t *, listNodeArray, 0);
00617       return result;
00618     }
00619   else
00620     {
00621       return NIL (Rlp_Formula_t);
00622     }
00623 }
00624 
00625 
00626 /** \brief  Set the type of a given Rlp_Formula_t based on the attribute
00627   */
00628 
00629 static void
00630 setEntryType (Rlp_Formula_t * entry, char *attribute)
00631 {
00632   if (util_strequal (attribute, "ack"))
00633     {
00634       entry->type = Rlp_Ack_c;
00635       return;
00636     }
00637   if (util_strequal (attribute, "byte_jump"))
00638     {
00639       entry->type = Rlp_Byte_Jump_c;
00640       return;
00641     }
00642   if (util_strequal (attribute, "byte_test"))
00643     {
00644       entry->type = Rlp_Byte_Test_c;
00645       return;
00646     }
00647   if (util_strequal (attribute, "content"))
00648     {
00649       entry->type = Rlp_Content_c;
00650       return;
00651     }
00652   if (util_strequal (attribute, "depth"))
00653     {
00654       entry->type = Rlp_Depth_c;
00655       return;
00656     }
00657   if (util_strequal (attribute, "distance"))
00658     {
00659       entry->type = Rlp_Distance_c;
00660       return;
00661     }
00662   if (util_strequal (attribute, "dsize"))
00663     {
00664       entry->type = Rlp_Dsize_c;
00665       return;
00666     }
00667   if (util_strequal (attribute, "flags"))
00668     {
00669       entry->type = Rlp_Flags_c;
00670       return;
00671     }
00672   if (util_strequal (attribute, "fragbits"))
00673     {
00674       entry->type = Rlp_Fragbits_c;
00675       return;
00676     }
00677   if (util_strequal (attribute, "icmp_id"))
00678     {
00679       entry->type = Rlp_Icmp_Id_c;
00680       return;
00681     }
00682   if (util_strequal (attribute, "icmp_seq"))
00683     {
00684       entry->type = Rlp_Icmp_Seq_c;
00685       return;
00686     }
00687   if (util_strequal (attribute, "icode"))
00688     {
00689       entry->type = Rlp_Icode_c;
00690       return;
00691     }
00692   if (util_strequal (attribute, "id"))
00693     {
00694       entry->type = Rlp_Id_c;
00695       return;
00696     }
00697   if (util_strequal (attribute, "ipopts"))
00698     {
00699       entry->type = Rlp_IpOpts_c;
00700       return;
00701     }
00702   if (util_strequal (attribute, "ip_proto"))
00703     {
00704       entry->type = Rlp_Ip_Proto_c;
00705       return;
00706     }
00707   if (util_strequal (attribute, "itype"))
00708     {
00709       entry->type = Rlp_Itype_c;
00710       return;
00711     }
00712   if (util_strequal (attribute, "nocase"))
00713     {
00714       entry->type = Rlp_Nocase_c;
00715       return;
00716     }
00717   if (util_strequal (attribute, "offset"))
00718     {
00719       entry->type = Rlp_Offset_c;
00720       return;
00721     }
00722   if (util_strequal (attribute, "pcre"))
00723     {
00724       entry->type = Rlp_Pcre_c;
00725       return;
00726     }
00727   if (util_strequal (attribute, "rpc"))
00728     {
00729       entry->type = Rlp_Rpc_c;
00730       return;
00731     }
00732   if (util_strequal (attribute, "sameip"))
00733     {
00734       entry->type = Rlp_Sameip_c;
00735       return;
00736     }
00737   if (util_strequal (attribute, "seq"))
00738     {
00739       entry->type = Rlp_Seq_c;
00740       return;
00741     }
00742   if (util_strequal (attribute, "ttl"))
00743     {
00744       entry->type = Rlp_Ttl_c;
00745       return;
00746     }
00747   if (util_strequal (attribute, "uricontent"))
00748     {
00749       entry->type = Rlp_Uricontent_c;
00750       return;
00751     }
00752   if (util_strequal (attribute, "within"))
00753     {
00754       entry->type = Rlp_Within_c;
00755       return;
00756     }
00757   if (util_strequal (attribute, "interface"))
00758     {
00759       entry->type = Rlp_Interface_c;
00760       return;
00761     }
00762   if (util_strequal (attribute, "sample"))
00763     {
00764       entry->type = Rlp_Sample_c;
00765       return;
00766     }
00767   fprintf (stderr, "Problem: unrecognized attribute %s, ignoring\n",
00768        attribute);
00769 }
00770 
00771 
00772 /**
00773   * \brief  Print a parse tree
00774   */
00775 
00776 int
00777 Rlp_ParsedRulePrint (Rlp_Formula_t * aTree)
00778 {
00779   while (aTree != NIL (Rlp_Formula_t))
00780     {
00781       Rlp_NodePrint (aTree->lchild);
00782       printf ("\n");
00783       aTree = cdr (aTree);
00784     }
00785   return 1;
00786 }
00787 
00788 
00789 /** \brief  Parse the raw text string that makes up the value.
00790  
00791 Implement by switch on the type of the entry.
00792 */
00793 
00794 static int
00795 parseRawValue (Rlp_Formula_t * entry)
00796 {
00797   switch (entry->type)
00798     {
00799 
00800     case Rlp_Nocase_c:
00801     case Rlp_Sameip_c:
00802       return 0;
00803 
00804     case Rlp_Ack_c:
00805     case Rlp_Depth_c:
00806     case Rlp_Distance_c:
00807     case Rlp_Icmp_Id_c:
00808     case Rlp_Icmp_Seq_c:
00809     case Rlp_Icode_c:
00810     case Rlp_Itype_c:
00811     case Rlp_Offset_c:
00812     case Rlp_Seq_c:
00813     case Rlp_Within_c:
00814       entry->rchild =
00815     (Rlp_Formula_t *) (Rlp_IntAttribute_t *)
00816     malloc (sizeof (Rlp_IntAttribute_t));
00817       sscanf ((char *) entry->lchild, "%d",
00818           (int *) &((Rlp_IntAttribute_t *) entry->rchild)->intEntry);
00819       return 0;
00820 
00821     case Rlp_Byte_Jump_c:
00822       return parseByteJump (entry);
00823     case Rlp_Byte_Test_c:
00824       return parseByteTest (entry);
00825     case Rlp_Content_c:
00826       return parseContent (entry);
00827     case Rlp_Pcre_c:
00828       return parsePcre (entry);
00829     case Rlp_Id_c:
00830       return parseIpProto (entry);  // this is not a cut and paste error, we can use the exact same struct
00831     case Rlp_Ip_Proto_c:
00832       return parseIpProto (entry);
00833     case Rlp_Dsize_c:
00834       return parseDsize (entry);
00835     case Rlp_Flags_c:
00836       return parseFlags (entry);
00837     case Rlp_Fragbits_c:
00838       return parseFragbits (entry);
00839     case Rlp_IpOpts_c:
00840       return parseIpOpts (entry);
00841     case Rlp_Rpc_c:
00842       return parseRpc (entry);
00843     case Rlp_Ttl_c:
00844       return parseTtl (entry);
00845     case Rlp_Uricontent_c:
00846       return parseUricontent (entry);
00847     case Rlp_Interface_c:
00848       return parseInterface (entry);
00849     case Rlp_Sample_c:
00850       return parseSample (entry);
00851 
00852     default:
00853       printf ("Problem - passed in an unknown type of formula, ignoring\n");
00854       assert (0);
00855     }
00856 
00857   printf ("Should never be here\n");
00858   return -1;
00859 }
00860 
00861 
00862 /**
00863   * \brief  Parse bytejump value string.
00864   * 
00865   * We aren't checking that big/little or dec/oct/hex etc are exclusive, relying
00866   * on input to be well formed.
00867   * 
00868   */
00869 
00870 static int
00871 parseByteJump (Rlp_Formula_t * entry)
00872 {
00873   entry->rchild =
00874     (Rlp_Formula_t *) (Rlp_ByteJumpAttribute_t *)
00875     malloc (sizeof (Rlp_ByteJumpAttribute_t));
00876 
00877   Rlp_ByteJumpAttribute_t *result = (Rlp_ByteJumpAttribute_t *) entry->rchild;
00878 
00879   result->bytesToConvert = result->offset = -1;
00880 
00881   result->relative = result->useLittleEndian = result->isString =
00882     result->isHex = result->isDec = result->isOct = result->doAlign = false;
00883 
00884   char *rawValue = (char *) entry->lchild;
00885 
00886   sscanf (rawValue, "%d , %d", &(result->bytesToConvert), &(result->offset));
00887 
00888   if (strstr (rawValue, "relative"))
00889     {
00890       result->relative = true;
00891     }
00892   if (strstr (rawValue, "big"))
00893     {
00894       result->useLittleEndian = false;
00895     }
00896   if (strstr (rawValue, "little"))
00897     {
00898       result->useLittleEndian = true;
00899     }
00900   if (strstr (rawValue, "string"))
00901     {
00902       result->isString = true;
00903     }
00904   if (strstr (rawValue, "hex"))
00905     {
00906       result->isHex = true;
00907     }
00908   if (strstr (rawValue, "dec"))
00909     {
00910       result->isDec = true;
00911     }
00912   if (strstr (rawValue, "oct"))
00913     {
00914       result->isOct = true;
00915     }
00916   if (strstr (rawValue, "align"))
00917     {
00918       result->doAlign = true;
00919     }
00920 
00921   return 0;
00922 
00923 };
00924 
00925 
00926 /**
00927   * \brief  Parse bytetest string.
00928   * 
00929   * We aren't checking that 
00930   * big/little or dec/oct/hex etc are exclusive, relying
00931   * on input to be well formed.
00932   * 
00933   */
00934 
00935 static int
00936 parseByteTest (Rlp_Formula_t * entry)
00937 {
00938   entry->rchild =
00939     (Rlp_Formula_t *) (Rlp_ByteTestAttribute_t *)
00940     malloc (sizeof (Rlp_ByteTestAttribute_t));
00941 
00942   Rlp_ByteTestAttribute_t *result = (Rlp_ByteTestAttribute_t *) entry->rchild;
00943 
00944   //  <bytes_to_convert>, <operator>, <value>, <offset>
00945   // [, [relative],[big],[little],[string],[hex],[dec],[oct] ]
00946 
00947   result->relative = result->useLittleEndian = result->isString =
00948     result->isHex = result->isDec = result->isOct = false;
00949 
00950   char *rawValue = (char *) entry->lchild;
00951 
00952   // this needs to be fixed - since value may be encoded in hex or oct
00953   sscanf (rawValue, "%d , %c , %d , %d", &(result->bytesToConvert),
00954       &(result->check ), &(result->value), &(result->offset));
00955 
00956   if (strstr (rawValue, "relative"))
00957     {
00958       result->relative = true;
00959     }
00960   if (strstr (rawValue, "big"))
00961     {
00962       result->useLittleEndian = false;
00963     }
00964   if (strstr (rawValue, "little"))
00965     {
00966       result->useLittleEndian = true;
00967     }
00968   if (strstr (rawValue, "string"))
00969     {
00970       result->isString = true;
00971     }
00972   if (strstr (rawValue, "hex"))
00973     {
00974       result->isHex = true;
00975     }
00976   if (strstr (rawValue, "dec"))
00977     {
00978       result->isDec = true;
00979     }
00980   if (strstr (rawValue, "oct"))
00981     {
00982       result->isOct = true;
00983     }
00984 
00985   return 0;
00986 }
00987 
00988 
00989 /**
00990   * \brief  Parse ip_proto string
00991   * 
00992   */
00993 
00994 static int
00995 parseIpProto (Rlp_Formula_t * entry)
00996 {
00997   char *rawValue = (char *) entry->lchild;
00998 
00999   entry->rchild =
01000     (Rlp_Formula_t *) (Rlp_IpProtoAttribute_t *)
01001     malloc (sizeof (Rlp_IpProtoAttribute_t));
01002   Rlp_IpProtoAttribute_t *result = (Rlp_IpProtoAttribute_t *) entry->rchild;
01003 
01004   result->greaterThan = result->lessThan = false;
01005   result->negated = false;
01006 
01007   if (strchr (rawValue, '<'))
01008     {
01009       result->lessThan = true;
01010     }
01011   if (strchr (rawValue, '>'))
01012     {
01013       result->greaterThan = true;
01014     }
01015   if (strchr (rawValue, '!'))
01016     {
01017       result->negated = true;
01018     }
01019 
01020   while (!isdigit (*rawValue))
01021     rawValue++;
01022 
01023   sscanf (rawValue, "%d", &(result->value));
01024 
01025   return 0;
01026 }
01027 
01028 
01029 /** \brief  Parse dvalue string */
01030 
01031 static int
01032 parseDsize (Rlp_Formula_t * entry)
01033 {
01034   char *rawValue = (char *) entry->lchild;
01035 
01036   entry->rchild =
01037     (Rlp_Formula_t *) (Rlp_DsizeAttribute_t *)
01038     malloc (sizeof (Rlp_DsizeAttribute_t));
01039   Rlp_DsizeAttribute_t *result = (Rlp_DsizeAttribute_t *) entry->rchild;
01040 
01041   result->greaterThan = result->lessThan = false;
01042   result->dsize = -1;
01043 
01044   if (strchr (rawValue, '<'))
01045     {
01046       result->lessThan = true;
01047     }
01048   if (strchr (rawValue, '>'))
01049     {
01050       result->greaterThan = true;
01051     }
01052 
01053   while (!isdigit (*rawValue))
01054     rawValue++;
01055 
01056   sscanf (rawValue, "%d", &(result->dsize));
01057 
01058   return 0;
01059 }
01060 
01061 
01062 /** \brief  Parse sample */
01063 
01064 static int
01065 parseSample (Rlp_Formula_t * entry)
01066 {
01067   char *rawValue = (char *) entry->lchild;
01068 
01069   Rlp_SampleAttribute_t *result =
01070     (Rlp_SampleAttribute_t *) malloc (sizeof (Rlp_SampleAttribute_t));
01071 
01072   entry->rchild = (Rlp_Formula_t *) result;
01073 
01074   sscanf (rawValue, "%lf", &result->threshold);
01075   if (result->threshold > 1.0)
01076     {
01077       printf
01078     ("Warning, sampling threshold %f is bigger than 1.0, using 1.0\n",
01079      result->threshold);
01080       result->threshold = 1.0;
01081     }
01082   else if (result->threshold < 0.0)
01083     {
01084       printf
01085     ("Warning, sampling threshold %f is smaller than 0.0, using 0.0\n",
01086      result->threshold);
01087       result->threshold = 0.0;
01088     }
01089 
01090   return 0;
01091 }
01092 
01093 
01094 /** \brief  Parse interface */
01095 
01096 static int
01097 parseInterface (Rlp_Formula_t * entry)
01098 {
01099   char *rawValue = (char *) entry->lchild;
01100 
01101   Rlp_IfAttribute_t *result =
01102     (Rlp_IfAttribute_t *) malloc (sizeof (Rlp_IfAttribute_t));
01103 
01104   entry->rchild = (Rlp_Formula_t *) result;
01105 
01106   result->ifName = strdup (rawValue);
01107   result->interface = NIL (Pkt_LibPcap_t);
01108 
01109   return 0;
01110 }
01111 
01112 
01113 /** \brief  Parse TTL */
01114 
01115 static int
01116 parseTtl (Rlp_Formula_t * entry)
01117 {
01118   char *rawValue = (char *) entry->lchild;
01119 
01120   Rlp_TtlAttribute_t *result =
01121     (Rlp_TtlAttribute_t *) malloc (sizeof (Rlp_TtlAttribute_t));
01122 
01123   entry->rchild = (Rlp_Formula_t *) result;
01124 
01125   result->lessThan = result->greaterThan = false;
01126   result->ttl = -1;
01127 
01128   if (strchr (rawValue, '<'))
01129     {
01130       result->lessThan = true;
01131     }
01132   if (strchr (rawValue, '>'))
01133     {
01134       result->greaterThan = true;
01135     }
01136 
01137   while (!isdigit (*rawValue))
01138     rawValue++;
01139 
01140   sscanf (rawValue, "%d", &(result->ttl));
01141 
01142   return 0;
01143 }
01144 
01145 
01146 /** \brief  Parse ipopts */
01147 
01148 static int
01149 parseIpOpts (Rlp_Formula_t * entry)
01150 {
01151   char *rawValue = (char *) entry->lchild;
01152   char rawValueWithoutSpaces[1000];
01153 
01154   Rlp_IpOptsAttribute_t *result =
01155     (Rlp_IpOptsAttribute_t *) malloc (sizeof (Rlp_IpOptsAttribute_t));
01156 
01157   entry->rchild = (Rlp_Formula_t *) result;
01158 
01159   result->ipOpt = Rlp_unassigned_c;
01160 
01161   int i;
01162   int length = 0;
01163   for (i = 0; i < (int) strlen (rawValue); i++)
01164     {
01165       if (!isspace (rawValue[i]))
01166     {
01167       rawValueWithoutSpaces[i] = rawValue[i];
01168       length++;
01169     }
01170     }
01171   rawValueWithoutSpaces[length] = '\0';
01172 
01173   if (util_strequal (rawValueWithoutSpaces, "rr"))
01174     {
01175       result->ipOpt = Rlp_rr_c;
01176     }
01177   if (util_strequal (rawValueWithoutSpaces, "eol"))
01178     {
01179       result->ipOpt = Rlp_eol_c;
01180     }
01181   if (util_strequal (rawValueWithoutSpaces, "nop"))
01182     {
01183       result->ipOpt = Rlp_nop_c;
01184     }
01185   if (util_strequal (rawValueWithoutSpaces, "ts"))
01186     {
01187       result->ipOpt = Rlp_ts_c;
01188     }
01189   if (util_strequal (rawValueWithoutSpaces, "sec"))
01190     {
01191       result->ipOpt = Rlp_sec_c;
01192     }
01193   if (util_strequal (rawValueWithoutSpaces, "lsrr"))
01194     {
01195       result->ipOpt = Rlp_lsrr_c;
01196     }
01197   if (util_strequal (rawValueWithoutSpaces, "lsrre"))
01198     {
01199       result->ipOpt = Rlp_lsrre_c;
01200     }
01201   if (util_strequal (rawValueWithoutSpaces, "ssrr"))
01202     {
01203       result->ipOpt = Rlp_ssrr_c;
01204     }
01205   if (util_strequal (rawValueWithoutSpaces, "satid"))
01206     {
01207       result->ipOpt = Rlp_satid_c;
01208     }
01209   if (result->ipOpt == Rlp_unassigned_c)
01210     {
01211       printf ("Hit unassigned ipOpt\n");
01212       assert (0);
01213     }
01214 
01215   return 0;
01216 }
01217 
01218 
01219 /**
01220   * \brief  Parse fragbits. 
01221   * 
01222   * \todo Not clear what is meant by 
01223   * + or -, so simply checking which chars are present.
01224   * 
01225   */
01226 
01227 static int
01228 parseFragbits (Rlp_Formula_t * entry)
01229 {
01230   char *rawValue = (char *) entry->lchild;
01231 
01232   Rlp_FragbitsAttribute_t *result =
01233     (Rlp_FragbitsAttribute_t *) malloc (sizeof (Rlp_FragbitsAttribute_t));
01234 
01235   entry->rchild = (Rlp_Formula_t *) result;
01236 
01237   result->RB = parseIndividualFlag (rawValue, 'R');
01238   result->MF = parseIndividualFlag (rawValue, 'M');
01239   result->DF = parseIndividualFlag (rawValue, 'D');
01240 
01241   return 0;
01242 }
01243 
01244 
01245 /** \brief  Parse tcp flags. 
01246   
01247 \todo Not clear what is meant by 
01248 + or -, so simply checking which chars are present.
01249 If a char is not present, the default is don't care.
01250 Consequently, we're not differentiating wrt A and A+.
01251 */
01252 
01253 
01254 static int
01255 parseFlags (Rlp_Formula_t * entry)
01256 {
01257   char *rawValue = (char *) entry->lchild;
01258 
01259   Rlp_FlagsAttribute_t *result =
01260     (Rlp_FlagsAttribute_t *) malloc (sizeof (Rlp_FlagsAttribute_t));
01261 
01262   entry->rchild = (Rlp_Formula_t *) result;
01263 
01264   result->noFlagsSet = one_c;
01265 
01266   result->F = parseIndividualFlag (rawValue, 'F');
01267   result->S = parseIndividualFlag (rawValue, 'S');
01268   result->R = parseIndividualFlag (rawValue, 'R');
01269   result->P = parseIndividualFlag (rawValue, 'P');
01270   result->A = parseIndividualFlag (rawValue, 'A');
01271   result->U = parseIndividualFlag (rawValue, 'U');
01272   result->r_2 = parseIndividualFlag (rawValue, 'E');
01273   result->r_1 = parseIndividualFlag (rawValue, 'C');
01274 
01275   if ((result->F != X_c) ||
01276       (result->S != X_c) ||
01277       (result->R != X_c) ||
01278       (result->P != X_c) ||
01279       (result->A != X_c) ||
01280       (result->U != X_c) || (result->r_2 != X_c) || (result->r_1 != X_c))
01281     {
01282       result->noFlagsSet = zero_c;
01283     }
01284 
01285   return 0;
01286 }
01287 
01288 
01289 /** \brief Utility function to parse tcp flags */
01290 
01291 static Rlp_FlagType_t
01292 parseIndividualFlag (char *rawValue, char flag)
01293 {
01294   char *loc = strchr (rawValue, flag);
01295   if (loc == NIL (char))
01296     {
01297       return X_c;
01298     }
01299   if (loc == rawValue)
01300     {
01301       // cant be negated;
01302       return one_c;
01303     }
01304   if (loc[-1] == '!')
01305     {
01306       return zero_c;
01307     }
01308   return one_c;
01309 }
01310 
01311 
01312 /** \brief  Parse rpc */
01313 
01314 static int
01315 parseRpc (Rlp_Formula_t * entry)
01316 {
01317   char *rawValue = (char *) entry->lchild;
01318   Rlp_RpcAttribute_t *result =
01319     (Rlp_RpcAttribute_t *) malloc (sizeof (Rlp_RpcAttribute_t));
01320   entry->rchild = (Rlp_Formula_t *) result;
01321 
01322   result->application = result->procedure = result->version = -1;
01323   result->anyProcedure = result->anyVersion = false;
01324 
01325   char tmp1Buf[100];
01326   char tmp2Buf[100];
01327   char tmp3Buf[100];
01328 
01329   int length = 0;
01330   while (*rawValue != ',')
01331     {
01332       tmp1Buf[length] = *rawValue;
01333       rawValue++;
01334       length++;
01335     }
01336   tmp1Buf[length] = '\0';
01337   rawValue++;           // get past the comma
01338 
01339   length = 0;
01340   while (*rawValue != ',')
01341     {
01342       *tmp2Buf = *rawValue;
01343       rawValue++;
01344       length++;
01345     }
01346   tmp2Buf[length] = '\0';
01347   rawValue++;           // get past the comma
01348 
01349   length = 0;
01350   while (*rawValue != '\0')
01351     {
01352       *tmp3Buf = *rawValue;
01353       rawValue++;
01354       length++;
01355     }
01356   tmp2Buf[length] = '\0';
01357 
01358   sscanf (tmp1Buf, "%d", &(result->application));
01359 
01360   if (strchr (tmp2Buf, '*'))
01361     {
01362       result->anyProcedure = true;
01363     }
01364   else
01365     {
01366       sscanf (tmp2Buf, "%d", &(result->procedure));
01367     }
01368 
01369   if (strchr (tmp3Buf, '*'))
01370     {
01371       result->anyVersion = true;
01372     }
01373   else
01374     {
01375       sscanf (tmp3Buf, "%d", &(result->version));
01376     }
01377 
01378   return 0;
01379 }
01380 
01381 
01382 /**
01383   * \brief  Parse content into a byte string
01384   * 
01385   * The value is in quotes, because the content
01386   * is specified using content:"abc" so we need to remove
01387   * the trailing and starting quotes before parsing.
01388   * 
01389   * \todo are we handling escaped | correctly?
01390   * 
01391   */
01392 
01393 static int
01394 parseContent (Rlp_Formula_t * entry)
01395 {
01396   util_byte_array_t *tmpResult;
01397   util_byte_array_t *result = util_byte_array_create (NIL (char), 0);
01398 
01399   bool negated = false;
01400   util_byte_array_t *tmpByteArray;
01401 
01402   // this is to remove the beginning and trailing " 
01403   char *rawValue = strdup (((char *) (entry->lchild)));
01404   RLP_SKIP_SPACE (rawValue);    // get rid of any leading spaces
01405   if (*rawValue == '!')
01406     {
01407       // this is a negated formula
01408       negated = true;
01409       rawValue++;
01410       RLP_SKIP_SPACE (rawValue);
01411     }
01412   assert (*rawValue == '"');
01413 
01414   // there may be space between the quote and the semicolon!
01415   // hard bug to find ( content:" --use-compress-program" ; )
01416   int lastQuoteIndex = strlen (rawValue) - 1;
01417   while (rawValue[lastQuoteIndex] != '"')
01418     {
01419       lastQuoteIndex--;
01420     }
01421   rawValue[lastQuoteIndex] = '\0';
01422   rawValue++;           // rawValue past the first quote
01423 
01424   entry->rchild =
01425     (Rlp_Formula_t *) (Rlp_ContentAttribute_t *)
01426     malloc (sizeof (Rlp_ContentAttribute_t));
01427   ((Rlp_ContentAttribute_t *) entry->rchild)->negated = negated;
01428   ((Rlp_ContentAttribute_t *) entry->rchild)->byteArray = result;
01429 
01430   // first split into a series of strings, some bytecode, some strings
01431   // then convert bytecode to byte-array, then de-escape strings, then
01432   // merge to one
01433 
01434   char byteCodeBuffer[1000];
01435   char textBuffer[1000];
01436   char tmpBuffer[1000];
01437   char *tmpPtr;
01438 
01439   while (1)
01440     {
01441 
01442       if (*rawValue == '|')
01443     {
01444       rawValue++;
01445       tmpPtr = byteCodeBuffer;
01446       while (*rawValue != '|')
01447         {
01448           *tmpPtr = *rawValue;
01449           rawValue++;
01450           tmpPtr++;
01451         }
01452       rawValue++;       // get past the ending |
01453       *tmpPtr = '\0';
01454 
01455       tmpPtr = strdup (byteCodeBuffer);
01456       tmpByteArray = Rlp_ByteCodeToByteArray (byteCodeBuffer);
01457       tmpResult = util_byte_array_join (result, tmpByteArray);
01458       util_byte_array_free (tmpByteArray);
01459       util_byte_array_free (result);
01460       result = tmpResult;
01461       ((Rlp_ContentAttribute_t *) entry->rchild)->byteArray = result;
01462     }
01463       if (*rawValue == '\0')
01464     {
01465       break;
01466     }
01467       tmpPtr = textBuffer;
01468       while (1)
01469     {
01470       if (*rawValue == '\0')
01471         {
01472           break;
01473         }
01474       if (*rawValue == '|' && rawValue[-1] != '\\')
01475         {
01476           break;
01477         }
01478       *tmpPtr = *rawValue;
01479       tmpPtr++;
01480       rawValue++;
01481     }
01482       *tmpPtr = '\0';
01483 
01484       int j = 0;
01485       int i;
01486       for (i = 0; i < (int) strlen (textBuffer); i++)
01487     {
01488       if ((textBuffer[i] == '\\' && textBuffer[i + 1] == ':')
01489           || (textBuffer[i] == '\\' && textBuffer[i + 1] == ';')
01490           || (textBuffer[i] == '\\' && textBuffer[i + 1] == '\\')
01491           || (textBuffer[i] == '\\' && textBuffer[i + 1] == '|')
01492           || (textBuffer[i] == '\\' && textBuffer[i + 1] == '"'))
01493         {
01494           i++;
01495         }
01496       tmpBuffer[j] = textBuffer[i];
01497       j++;
01498     }
01499 
01500       tmpByteArray = util_byte_array_create (tmpBuffer, j);
01501       tmpResult = util_byte_array_join (result, tmpByteArray);
01502       util_byte_array_free (tmpByteArray);
01503       util_byte_array_free (result);
01504       result = tmpResult;
01505       ((Rlp_ContentAttribute_t *) entry->rchild)->byteArray = result;
01506     }
01507 
01508   if (false)
01509     util_byte_array_print (result);
01510 
01511   return 0;
01512 }
01513 
01514 /**
01515   * \brief  Convert byte code to a byte array.
01516   * 
01517   * Input assumed to be in hex, with possible whitespace.
01518   * 
01519   */
01520 
01521 util_byte_array_t *
01522 Rlp_ByteCodeToByteArray (char *byteCode)
01523 {
01524   util_byte_array_t *result =
01525     (util_byte_array_t *) malloc (sizeof (util_byte_array_t));
01526 
01527   int length = 0;
01528   unsigned char tmpBuf[1000];
01529   unsigned char *tmpPtr = (unsigned char *) byteCode;
01530 
01531   while (1)
01532     {
01533       while (isspace (*tmpPtr))
01534     {
01535       tmpPtr++;
01536     }
01537       if (*tmpPtr == '\0')
01538     {
01539       break;
01540     }
01541       assert ((('0' <= *tmpPtr) && (*tmpPtr <= '9')) ||
01542           (('a' <= *tmpPtr) && (*tmpPtr <= 'f')) ||
01543           (('A' <= *tmpPtr) && (*tmpPtr <= 'F')));
01544       int msb = hexToInt (*tmpPtr);
01545       tmpPtr++;
01546 
01547       // there are examples where the bytecode has white space between
01548       // succ chars
01549 
01550       while (isspace (*tmpPtr))
01551     {
01552       tmpPtr++;
01553     }
01554       if (*tmpPtr == '\0')
01555     {
01556       printf ("Malformed bytecode - odd number of hex entries\n");
01557       assert (0);
01558     }
01559 
01560       int lsb = hexToInt (*tmpPtr);
01561       unsigned char byte = 16 * msb + lsb;
01562       tmpPtr++;
01563       tmpBuf[length] = byte;
01564       length++;
01565     }
01566   result->length = length;
01567   result->bytes = (char *) malloc (length * sizeof (unsigned char));
01568   memcpy (result->bytes, tmpBuf, length);
01569 
01570   return result;
01571 }
01572 
01573 
01574 /**
01575   * \brief  Convert a char representing an integer in hex to corresp int
01576   */
01577 
01578 static int
01579 hexToInt (char hexChar)
01580 {
01581   int result = -1;
01582   if (('0' <= hexChar) && (hexChar <= '9'))
01583     {
01584       result = hexChar - '0';
01585     }
01586   if (('a' <= hexChar) && (hexChar <= 'f'))
01587     {
01588       result = 10 + (hexChar - 'a');
01589     }
01590   if (('A' <= hexChar) && (hexChar <= 'F'))
01591     {
01592       result = 10 + (hexChar - 'A');
01593     }
01594   assert (result != -1);
01595 
01596   return result;
01597 }
01598 
01599 
01600 /**
01601   * \brief  Parse uricontent
01602   * 
01603   * Handle exactly as a content string; 
01604   * the difference is in the checking.
01605   * 
01606   */
01607 
01608 static int
01609 parseUricontent (Rlp_Formula_t * entry)
01610 {
01611   return parseContent (entry);
01612 }
01613 
01614 
01615 /**
01616   * \brief  Print a node, which is assumed to be an entry in a parse tree.
01617   * 
01618   */
01619 
01620 int
01621 Rlp_NodePrint (Rlp_Formula_t * entry)
01622 {
01623   Rlp_ByteJumpAttribute_t *byteJumpAttrib;
01624   Rlp_ByteTestAttribute_t *byteTestAttrib;
01625   Rlp_DsizeAttribute_t *dsizeAttrib;
01626   util_byte_array_t *byteArray;
01627   Rlp_FlagsAttribute_t *flagsAttrib;
01628   Rlp_FragbitsAttribute_t *fragbitsAttrib;
01629   Rlp_IpOptsAttribute_t *ipoptsAttrib;
01630   char *ipoptsString;
01631   Rlp_TtlAttribute_t *ttlAttrib;
01632   Rlp_RpcAttribute_t *rpcAttrib;
01633 
01634   if (entry == NIL (Rlp_Formula_t))
01635     {
01636       return 0;
01637     }
01638 
01639   printf ("Adnan ");
01640 
01641   switch (entry->type)
01642     {
01643 
01644 
01645     case Rlp_Nocase_c:
01646       printf ("nocase; ");
01647       break;
01648     case Rlp_Sameip_c:
01649       printf ("sameip; ");
01650       break;
01651 
01652     case Rlp_Ack_c:
01653       printf ("ack:%d ", ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01654       break;
01655     case Rlp_Depth_c:
01656       printf ("depth:%d ",
01657           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01658       break;
01659     case Rlp_Distance_c:
01660       printf ("distance:%d ",
01661           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01662       break;
01663     case Rlp_Icmp_Id_c:
01664       printf ("icmp:%d ", ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01665       break;
01666     case Rlp_Icmp_Seq_c:
01667       printf ("icmp_seq:%d ",
01668           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01669       break;
01670     case Rlp_Icode_c:
01671       printf ("icode:%d ",
01672           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01673       break;
01674     case Rlp_Ip_Proto_c:
01675       printf ("ip:%d ", ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01676       break;
01677     case Rlp_Itype_c:
01678       printf ("itype:%d ",
01679           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01680       break;
01681     case Rlp_Id_c:
01682       printf ("id:%d ", ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01683       break;
01684     case Rlp_Offset_c:
01685       printf ("offset:%d ",
01686           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01687       break;
01688     case Rlp_Seq_c:
01689       printf ("seq:%d ", ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01690       break;
01691     case Rlp_Within_c:
01692       printf ("within:%d ",
01693           ((Rlp_IntAttribute_t *) (entry->rchild))->intEntry);
01694       break;
01695 
01696     case Rlp_Byte_Jump_c:
01697       byteJumpAttrib = (Rlp_ByteJumpAttribute_t *) entry->rchild;
01698       printf ("byte_jump:%d,%d", byteJumpAttrib->bytesToConvert,
01699           byteJumpAttrib->offset);
01700       if (byteJumpAttrib->relative)
01701     {
01702       printf (",relative");
01703     }
01704       if (byteJumpAttrib->useLittleEndian)
01705     {
01706       printf (",little");
01707     }
01708       if (byteJumpAttrib->isString)
01709     {
01710       printf (",string");
01711     }
01712       if (byteJumpAttrib->isHex)
01713     {
01714       printf (",hex");
01715     }
01716       if (byteJumpAttrib->isOct)
01717     {
01718       printf (",oct");
01719     }
01720       if (byteJumpAttrib->isDec)
01721     {
01722       printf (",dec");
01723     }
01724       if (byteJumpAttrib->doAlign)
01725     {
01726       printf (",align");
01727     }
01728       printf (" ");
01729       break;
01730 
01731     case Rlp_Byte_Test_c:
01732       byteTestAttrib = (Rlp_ByteTestAttribute_t *) entry->rchild;
01733       printf ("byte_test:%d,%c,%d,%d", byteTestAttrib->bytesToConvert,
01734           byteTestAttrib->check,
01735           byteTestAttrib->value, byteTestAttrib->offset);
01736       if (byteTestAttrib->relative)
01737     {
01738       printf (",relative");
01739     }
01740       if (byteTestAttrib->useLittleEndian)
01741     {
01742       printf (",little");
01743     }
01744       if (byteTestAttrib->isString)
01745     {
01746       printf (",string");
01747     }
01748       if (byteTestAttrib->isHex)
01749     {
01750       printf (",hex");
01751     }
01752       if (byteTestAttrib->isOct)
01753     {
01754       printf (",oct");
01755     }
01756       if (byteTestAttrib->isDec)
01757     {
01758       printf (",dec");
01759     }
01760       printf (" ");
01761       break;
01762 
01763     case Rlp_Content_c:
01764     case Rlp_Uricontent_c:
01765       byteArray = (util_byte_array_t *) entry->rchild;
01766       printf ("%s: ",
01767           (entry->type == Rlp_Content_c) ? "content" : "uricontent");
01768       util_byte_array_free (byteArray);
01769       break;
01770 
01771     case Rlp_Dsize_c:
01772       dsizeAttrib = (Rlp_DsizeAttribute_t *) entry->rchild;
01773       printf ("dsize:%s%d ", (dsizeAttrib->greaterThan ? ">" :
01774                   (dsizeAttrib->lessThan ? "<" : "")),
01775           dsizeAttrib->dsize);
01776       break;
01777 
01778     case Rlp_Flags_c:
01779       flagsAttrib = (Rlp_FlagsAttribute_t *) entry->rchild;
01780       printf ("flags:%s%s%s%s%s%s%s%s ",
01781           flagsAttrib->F ? "F" : "",
01782           flagsAttrib->S ? "S" : "",
01783           flagsAttrib->R ? "R" : "",
01784           flagsAttrib->P ? "P" : "",
01785           flagsAttrib->A ? "A" : "",
01786           flagsAttrib->U ? "U" : "",
01787           flagsAttrib->r_2 ? "2" : "", flagsAttrib->r_1 ? "1" : "");
01788       break;
01789 
01790     case Rlp_Fragbits_c:
01791       fragbitsAttrib = (Rlp_FragbitsAttribute_t *) entry->rchild;
01792       printf ("flags:%s%s%s ",
01793           fragbitsAttrib->RB ? "R" : "",
01794           fragbitsAttrib->MF ? "M" : "", fragbitsAttrib->DF ? "D" : "");
01795       break;
01796 
01797     case Rlp_IpOpts_c:
01798       ipoptsAttrib = (Rlp_IpOptsAttribute_t *) entry->rchild;
01799       switch (ipoptsAttrib->ipOpt)
01800     {
01801     case Rlp_unassigned_c:
01802       ipoptsString = "---UNASSIGNED";
01803       break;
01804     case Rlp_rr_c:
01805       ipoptsString = "rr";
01806       break;
01807     case Rlp_eol_c:
01808       ipoptsString = "eol";
01809       break;
01810     case Rlp_nop_c:
01811       ipoptsString = "nop";
01812       break;
01813     case Rlp_ts_c:
01814       ipoptsString = "ts";
01815       break;
01816     case Rlp_sec_c:
01817       ipoptsString = "sec";
01818       break;
01819     case Rlp_lsrr_c:
01820       ipoptsString = "lsrr";
01821       break;
01822     case Rlp_lsrre_c:
01823       ipoptsString = "lsrre";
01824       break;
01825     case Rlp_ssrr_c:
01826       ipoptsString = "ssrr";
01827       break;
01828     case Rlp_satid_c:
01829       ipoptsString = "satid";
01830       break;
01831     default:
01832       printf ("panic, reached unknown case\n");
01833       assert (0);
01834     }
01835       printf ("ipopts:%s ", ipoptsString);
01836       break;
01837 
01838     case Rlp_Rpc_c:
01839       rpcAttrib = (Rlp_RpcAttribute_t *) entry->rchild;
01840       char application[100];
01841       char procedure[100];
01842       char version[100];
01843       sprintf (application, "%d", rpcAttrib->application);
01844       if (rpcAttrib->anyProcedure)
01845     {
01846       sprintf (procedure, "%s", "*");
01847     }
01848       else
01849     {
01850       sprintf (procedure, "%d", rpcAttrib->procedure);
01851     }
01852       if (rpcAttrib->anyVersion)
01853     {
01854       sprintf (version, "%s", "*");
01855     }
01856       else
01857     {
01858       sprintf (version, "%d", rpcAttrib->version);
01859     }
01860       printf ("rpc:%s,%s,%s ", application, procedure, version);
01861       break;
01862 
01863     case Rlp_Ttl_c:
01864       ttlAttrib = (Rlp_TtlAttribute_t *) entry->rchild;
01865       printf ("ttl:%s%d ", (ttlAttrib->greaterThan ? ">" :
01866                 (ttlAttrib->lessThan ? "<" : "")),
01867           ttlAttrib->ttl);
01868       break;
01869 
01870     default:
01871       printf ("Panic - passed in an unknown type of formula\n");
01872       assert (0);
01873     }
01874   return 0;
01875 }
01876 
01877 /** \brief  Read a bunch of L7 formulas from a file, return them in an array */
01878 
01879 array_t *
01880 Rlp_TestReadL7FormulasFromFile (char *fileName)
01881 {
01882 
01883   FILE *l7File = fopen (fileName, "r");
01884 
01885   if (l7File == NIL (FILE))
01886     {
01887       printf ("Could not open file %s, returning NIL\n", fileName);
01888     }
01889   array_t *result = array_alloc (Rlp_Formula_t *, 0);
01890 
01891   char tmpBuf[10000];
01892   while (1)
01893     {
01894       if (!fgets (tmpBuf, 10000, l7File))
01895     {
01896       return result;
01897     }
01898       array_t *aRule = Rlp_L7StringParse (tmpBuf);
01899       Rlp_Formula_t *aParsedRule =
01900     Rlp_CreateParseTreeFromAttribValuePairArray (aRule);
01901       array_insert_last (Rlp_Formula_t *, result, aParsedRule);
01902     }
01903   return result;
01904 }
01905 
01906 
01907 /** \brief  Get the L4 text from a rule */
01908 
01909 char *
01910 Rlp_GetL4ComponentFromRawRule (char *rawRule)
01911 {
01912   char tmpBuf[10000];
01913 
01914   strcpy (tmpBuf, rawRule);
01915 
01916   char *tmpPtr = strchr (tmpBuf, '(');
01917   *tmpPtr = '\0';
01918 
01919   tmpPtr = tmpBuf;
01920   while (*tmpPtr == ' ')
01921     {
01922       tmpPtr++;
01923     }
01924   if (util_strequalN (tmpPtr, "preprocess", strlen ("preprocess")))
01925     {
01926       tmpPtr += strlen ("preprocess");
01927       while (*tmpPtr == ' ')
01928     {
01929       tmpPtr++;
01930     }
01931     }
01932 
01933   return strdup (tmpPtr);
01934 }
01935 
01936 
01937 /** \brief  Get the L7 text from a rule */
01938 
01939 char *
01940 Rlp_GetL7ComponentFromRawRule (char *rawRule)
01941 {
01942   char tmpBuf[10000];
01943   char *beginPtr = strchr (rawRule, '(');
01944   char *endPtr = strrchr (rawRule, ')');
01945 
01946   assert (beginPtr != NIL (char));
01947   assert (endPtr != NIL (char));
01948 
01949   /* 
01950 
01951      '(' 'x' 's' 'a' ')'
01952      4   5   6   7   8
01953      ( 8 - 4 )  - 1 = 4 - 1 = 3
01954 
01955 
01956    */
01957 
01958   int length = (endPtr - beginPtr) - 1;
01959 
01960   strncpy (tmpBuf, beginPtr + 1, length);
01961   tmpBuf[length] = '\0';
01962 
01963   return strdup (tmpBuf);
01964 
01965 }
01966 
01967 
01968 /**
01969   * \brief  Get the action component from a rule
01970   * 
01971   * The assumption is that the rule consists of
01972   * layer 4 string, layer 7 string, which is enclosed
01973   * in parens, and then action string.  The right
01974   * parens symbol should NOT appear in the action string.
01975   * 
01976   */
01977 
01978 char *
01979 Rlp_GetActionComponentFromRawRule (char *rawRule)
01980 {
01981   char *beginPtr = strrchr (rawRule, ')');
01982   assert (beginPtr != NIL (char));
01983 
01984   // add + 1 to go pass the ) parens
01985   return strdup (beginPtr + 1);
01986 }
01987 
01988 
01989 /** \brief  Check if a given rule attribute is a comment */
01990 
01991 static bool
01992 isComment (char *attribute)
01993 {
01994   if (util_strequal (attribute, "msg") ||
01995       util_strequal (attribute, "classtype") ||
01996       util_strequal (attribute, "sid") ||
01997       util_strequal (attribute, "rev") ||
01998       util_strequal (attribute, "flow") ||
01999       util_strequal (attribute, "reference"))
02000     {
02001       return true;
02002     }
02003   else
02004     {
02005       return false;
02006     }
02007 }
02008 
02009 
02010 /** \brief  Free an array_t and the strings in it */
02011 
02012 int
02013 Rlp_FreeArrayOfStrings (array_t * stringArray)
02014 {
02015   int i;
02016   for (i = 0; i < array_n (stringArray); i++)
02017     {
02018       char *aString = array_fetch (char *, stringArray, i);
02019       free (aString);
02020     }
02021   array_free (stringArray);
02022   return 0;
02023 }
02024 
02025 
02026 /**
02027   * \brief  Return a hash containing all the content checks for in the given rule
02028   * 
02029   * We're passing in an array containing Rlp_L7Check_t entries - these
02030   * are all the L7 checks in the corresponding rule.
02031   */
02032 
02033 st_table *
02034 Rlp_L7CheckGetContentChecks (array_t * L7CheckArray)
02035 {
02036   st_table *result = Hash_InitTable ( (int(*)()) st_ptrcmp, (int(*)()) st_ptrhash);
02037 
02038   int i;
02039   for (i = 0; i < array_n (L7CheckArray); i++)
02040     {
02041       Rlp_L7Check_t *aCheck = array_fetch (Rlp_L7Check_t *, L7CheckArray, i);
02042       if ((aCheck->type == Rlp_L7ContentCheck_c) ||
02043       (aCheck->type == Rlp_L7UriContentCheck_c))
02044     {
02045       // Hash_Insert( result, ( char * ) aCheck->entryData.contentCheck->content, (char * ) 0 );
02046       // We are inserting the check itself, rather than just the strings 
02047       // because there is (at least) one place where we need to know
02048       // more thenan the string - specifically, we need to know if the check 
02049       // is negated to not put the string in the DFA
02050       Hash_Insert (result, (char *) aCheck->entryData.contentCheck,
02051              (char *) 0);
02052     }
02053     }
02054   return result;
02055 }
02056 
02057 
02058 /** \brief  Code to test parsing of content */
02059 
02060 void
02061 Rlp_TestParseContent (char *fileName)
02062 {
02063   FILE *fp = fopen (fileName, "r");
02064   util_byte_array_t USE *aByteArray;
02065   st_table *uniqStrings =
02066     Hash_InitTable ( (int(*)()) util_byte_array_cmp,  (int(*)()) util_byte_array_hash);
02067   st_table *dups = Hash_InitTable ( (int(*)()) strcmp,  (int(*)()) st_strhash);
02068   int count;
02069 
02070   char tmpBuf[10000];
02071   int i = 0;
02072   while (1)
02073     {
02074       i++;
02075       if (!fgets (tmpBuf, 10000, fp))
02076     {
02077       break;
02078     }
02079       // get rid of trailing newline
02080       tmpBuf[strlen (tmpBuf) - 1] = '\0';
02081       Rlp_Formula_t tmpNode;
02082       tmpNode.lchild = (Rlp_Formula_t *) strdup (tmpBuf);
02083       parseContent (&tmpNode);
02084       if (Hash_Lookup
02085       (uniqStrings,
02086        (char *) ((Rlp_ContentAttribute_t *) tmpNode.rchild)->byteArray,
02087        (char **) &count))
02088     {
02089       Hash_Insert (uniqStrings,
02090              (char *) ((Rlp_ContentAttribute_t *) tmpNode.rchild)->
02091              byteArray, (char *) count + 1);
02092       Hash_Insert (dups, (char *) tmpNode.lchild,
02093              (char *) ((Rlp_ContentAttribute_t *) tmpNode.rchild)->
02094              byteArray);
02095     }
02096       else
02097     {
02098       Hash_Insert (uniqStrings,
02099              (char *) ((Rlp_ContentAttribute_t *) tmpNode.rchild)->
02100              byteArray, (char *) 1);
02101     }
02102     }
02103 
02104 }
02105 
02106 
02107 /** \brief  Adds a mapping from a macro name to definition
02108   *
02109   *     Typically anEntry will be "var foo 192.168.1.1"
02110   *     We will add "foo" to the
02111   *     table, and map it to "192.168.1.1"
02112   *
02113   */
02114 
02115 int
02116 Rlp_UpdateDefineTable (st_table * aTable, char *anEntry)
02117 {
02118   char varBuf[1000];
02119   // say anEntry is "var   foo   80"
02120   char *beginSymbolPtr = anEntry + 3;   // points to "   foo 80"
02121   while (isspace (*beginSymbolPtr))
02122     {
02123       beginSymbolPtr++;
02124     }
02125   // now it's pointing to "foo 80"
02126 
02127   char *endSymbolPtr = strchr (beginSymbolPtr, ' ');
02128   // endSymbolPtr is pointing to " 80"
02129   while (isspace (*endSymbolPtr))
02130     {
02131       endSymbolPtr--;
02132     }
02133   // now endSymbolPointer is pointing to "o 80"
02134   endSymbolPtr++;
02135   // now endSymbolPointer is pointing to " 80"
02136 
02137   int length = endSymbolPtr - beginSymbolPtr;
02138   strncpy (varBuf, beginSymbolPtr, length);
02139   varBuf[length] = '\0';
02140   char *symbolName = strdup (varBuf);
02141 
02142   char *symbolValue;
02143   while (isspace (*endSymbolPtr))
02144     {
02145       endSymbolPtr++;
02146     }
02147   // now endSymbolPtr points to "80"
02148   symbolValue = strdup (endSymbolPtr);
02149   // remove any trailing whitespace
02150   char *tmpPtr = symbolValue + strlen (symbolValue) - 1;
02151   while (isspace (*tmpPtr))
02152     {
02153       *tmpPtr = '\0';
02154       tmpPtr--;
02155     }
02156   Hash_Insert (aTable, symbolName, symbolValue);
02157   return 0;
02158 }
02159 
02160 
02161 /** \brief  Parse pcre */
02162 
02163 static int
02164 parsePcre (Rlp_Formula_t * entry)
02165 {
02166   int errorOffset;
02167   const char *error;
02168 
02169   // this is to remove the beginning and trailing "
02170   char *rawValue = strdup (((char *) (entry->lchild)));
02171   RLP_SKIP_SPACE (rawValue);    // get rid of any leading spaces
02172   assert (*rawValue == '"');
02173   // there may be space between the quote and the semicolon!
02174   // hard bug to find ( content:" --use-compress-program" ; )
02175   int lastQuoteIndex = strlen (rawValue) - 1;
02176   while (rawValue[lastQuoteIndex] != '"')
02177     {
02178       lastQuoteIndex--;
02179     }
02180   rawValue[lastQuoteIndex] = '\0';
02181   rawValue++;           // rawValue past the first quote
02182 
02183   Rlp_PcreAttribute_t *result =
02184     (Rlp_PcreAttribute_t *) malloc (sizeof (Rlp_PcreAttribute_t));
02185   entry->rchild = (Rlp_Formula_t *) result;
02186 
02187   result->reText = rawValue;
02188   result->re = pcre_compile (result->reText, 0, &error, &errorOffset, NULL);
02189   result->pe = pcre_study (result->re, 0, &error);
02190 
02191   return 0;
02192 }