Azinix

rlpL4.c

Go to the documentation of this file.
00001 /** \file rlpL4.c
00002 
00003 
00004  \brief Routines for building a L4 check structure from a formula.
00005 
00006 ******************************************************************************/
00007 
00008 #include "rlp.h"
00009 
00010 
00011 /**AutomaticStart*************************************************************/
00012 
00013 static int L4CheckStructPopulateComponentStrings (Rlp_L4Check_t * result,
00014                           char *rawFormula);
00015 static char *computeComponentN (char *aString, int N);
00016 static Rlp_OperatorEnum_t computeTypeFromString (char *aString);
00017 static Rlp_Formula_t *createIpFormulaFromList (char *aString);
00018 static Rlp_Formula_t *processLeafIpFormula (char *leafString);
00019 static char *clearBrackets (char *text);
00020 
00021 /**AutomaticEnd***************************************************************/
00022 
00023 
00024 /**
00025   * \brief  Allocate an L4 check struct
00026   * 
00027   * Initialize entries to NIL, which indicates
00028   * an any in that field
00029   * 
00030   */
00031 
00032 Rlp_L4Check_t *
00033 Rlp_AllocL4CheckStruct ()
00034 {
00035   Rlp_L4Check_t *result = (Rlp_L4Check_t *) malloc (sizeof (Rlp_L4Check_t));
00036   result->type = Rlp_Undef_c;
00037 
00038   result->srcIp = NIL (Rlp_Formula_t);
00039   result->srcPort = NIL (Rlp_Formula_t);
00040   result->destIp = NIL (Rlp_Formula_t);
00041   result->destPort = NIL (Rlp_Formula_t);
00042 
00043   return result;
00044 }
00045 
00046 
00047 /**
00048   * \brief  Create an l4 check struct from a raw formula
00049   */
00050 
00051 Rlp_L4Check_t *
00052 Rlp_CreateL4CheckFromRawFormula (char *rawFormula)
00053 {
00054   Rlp_L4Check_t *result = Rlp_AllocL4CheckStruct ();
00055   L4CheckStructPopulateComponentStrings (result, rawFormula);
00056 
00057   result->type = computeTypeFromString (result->typeString);
00058 
00059   result->srcIpString = clearBrackets (result->srcIpString);
00060   result->srcIp = Rlp_ComputeIpFormulaFromString (result->srcIpString);
00061   result->srcPort = Rlp_ComputePortFormulaFromString (result->srcPortString);
00062 
00063   result->destIpString = clearBrackets (result->destIpString);
00064   result->destIp = Rlp_ComputeIpFormulaFromString (result->destIpString);
00065   result->destPort =
00066     Rlp_ComputePortFormulaFromString (result->destPortString);
00067 
00068   return result;
00069 }
00070 
00071 
00072 /**
00073   * \brief  Compute the raw strings defining each component of the L4 struct
00074   */
00075 
00076 static int
00077 L4CheckStructPopulateComponentStrings (Rlp_L4Check_t * result,
00078                        char *rawFormula)
00079 {
00080   char tmpBuf[1000];
00081   char *tmpPtr;
00082 
00083   // create a copy of rawformula with no leading whitespace,
00084   // and a single blank between fields
00085   while (isspace (*rawFormula))
00086     rawFormula++;
00087   tmpPtr = tmpBuf;
00088   while (*rawFormula != '\0')
00089     {
00090       if (!isspace (*rawFormula))
00091     {
00092       *tmpPtr = *rawFormula;
00093       tmpPtr++;
00094       rawFormula++;
00095     }
00096       else
00097     {
00098       *tmpPtr = ' ';
00099       tmpPtr++;
00100       while (isspace (*rawFormula))
00101         rawFormula++;
00102     }
00103     }
00104 
00105   // tcp $HN 80 -> 192.168.1.1 1234
00106   result->typeString = computeComponentN (tmpBuf, 0);
00107   result->srcIpString = computeComponentN (tmpBuf, 1);
00108   result->srcPortString = computeComponentN (tmpBuf, 2);
00109   result->destIpString = computeComponentN (tmpBuf, 4);
00110   result->destPortString = computeComponentN (tmpBuf, 5);
00111 
00112   return 0;
00113 
00114 }
00115 
00116 
00117 /**
00118   * \brief  Extract the N-th component of a string, assumed to be
00119   * separated by single blanks, no leading whitespace.
00120   * 
00121   * Numbering begins at 0, i.e., calling with "foo bar widget" 
00122   * with N=0 return foo.  Caller must free string.
00123   * 
00124   */
00125 
00126 static char *
00127 computeComponentN (char *aString, int N)
00128 {
00129   char *result;
00130 
00131   char *tmp1Ptr;
00132   char *tmp2Ptr = util_strchr_N (aString, ' ', N + 1);
00133   *tmp2Ptr = '\0';
00134 
00135   if (N > 0)
00136     {
00137       tmp1Ptr = util_strchr_N (aString, ' ', N);
00138     }
00139   else
00140     {
00141       tmp1Ptr = aString;    // assume no white space in the beginning
00142     }
00143 
00144   while (isspace (*tmp1Ptr))
00145     tmp1Ptr++;
00146   result = strdup (tmp1Ptr);
00147   *tmp2Ptr = ' ';       // restore the ' '
00148 
00149   return result;
00150 }
00151 
00152 
00153 /** \brief  Compute type from raw string */
00154 
00155 static Rlp_OperatorEnum_t
00156 computeTypeFromString (char *aString)
00157 {
00158   assert (util_strequal (aString, "icmp") ||
00159       util_strequal (aString, "ip") ||
00160       util_strequal (aString, "tcp") ||
00161       util_strequal (aString, "udp") ||
00162       util_strequal (aString, "generic") ||
00163       util_strequal (aString, "any"));
00164 
00165   if (util_strequal (aString, "icmp"))
00166     {
00167       return Rlp_Icmp_c;
00168     }
00169   if (util_strequal (aString, "ip"))
00170     {
00171       return Rlp_Ip_c;
00172     }
00173   if (util_strequal (aString, "tcp"))
00174     {
00175       return Rlp_Tcp_c;
00176     }
00177   if (util_strequal (aString, "udp"))
00178     {
00179       return Rlp_Udp_c;
00180     }
00181   if (util_strequal (aString, "any"))
00182     {
00183       return Rlp_Any_c;
00184     }
00185   if (util_strequal (aString, "generic"))
00186     {
00187       return Rlp_Generic_c;
00188     }
00189 
00190   return Rlp_Undef_c;
00191 }
00192 
00193 
00194 /**
00195   * \brief  Parse a raw string representing a set of IP addresses into
00196   * an Rlp_Formula_t
00197   * 
00198   Parse a raw string representing a set of IP addresses into
00199   an Rlp_Formula_t.  String is suppoed to be from the following
00200   grammar:
00201  
00202   <pre>
00203   !(foo) | !foo | foo,bar | IP/mask | IP |  DEFINE
00204   </pre>
00205   
00206   Note: we should not have whitespace anywhere.
00207   
00208   There is exactly one string in the ruleset that looks like
00209   [232.0.0.0/8,233.0.0.0/8,239.0.0.0/8]. For now, we're going
00210   to treat it by simply removing the leading and trailing brackets
00211   using the clearBrackets function call.
00212   
00213   */
00214 
00215 Rlp_Formula_t *
00216 Rlp_ComputeIpFormulaFromString (char *ipString)
00217 {
00218 
00219   char *tmpString = ipString;
00220   char *checkString;
00221   int length;
00222 
00223   if (util_strequal (ipString, "any"))
00224     {
00225       return new_node (Rlp_Any_c, NIL (Rlp_Formula_t), NIL (Rlp_Formula_t));
00226     }
00227 
00228   Rlp_Formula_t *result;
00229   Rlp_Formula_t *nextFormula;
00230   Rlp_Formula_t *subFormula;
00231 
00232   char tmpBuf[1000];
00233   int leftParensCount;
00234 
00235   tmpString = ipString;
00236   if (*tmpString == '!')
00237     {
00238       if (*(tmpString + 1) == '(')
00239     {
00240       leftParensCount = 1;
00241       checkString = tmpString + 2;
00242       leftParensCount = 1;
00243       while (1)
00244         {
00245           if (*checkString == ')')
00246         {
00247           leftParensCount--;
00248         }
00249           if (*checkString == '(')
00250         {
00251           leftParensCount++;
00252         }
00253           if (leftParensCount == 0)
00254         {
00255           break;
00256         }
00257           checkString++;
00258         }
00259       length = checkString - (tmpString + 2);
00260       strncpy (tmpBuf, tmpString + 2, length);
00261       tmpBuf[length] = '\0';
00262     }
00263       else
00264     {
00265       checkString = strchr (tmpString, ',');
00266       if (checkString == NIL (char))
00267         {
00268           checkString = strchr (tmpString, '\0');
00269         }
00270       length = checkString - tmpString;
00271       strncpy (tmpBuf, tmpString + 1, length);
00272     }
00273       subFormula = Rlp_ComputeIpFormulaFromString (tmpBuf);
00274       result = new_node (Rlp_Negation_c, subFormula, NIL (Rlp_Formula_t));
00275       if (*checkString == '\0')
00276     {
00277       return result;
00278     }
00279       else
00280     {
00281       nextFormula = Rlp_ComputeIpFormulaFromString (checkString);
00282       Rlp_Formula_t *list =
00283         new_node (Rlp_List_c, result, NIL (Rlp_Formula_t));
00284       list->rchild =
00285         new_node (Rlp_List_c, nextFormula, NIL (Rlp_Formula_t));
00286       return list;
00287     }
00288     }
00289   else
00290     {
00291       // don't have a neg formula
00292       if (!strchr (tmpString, ','))
00293     {
00294       // reached last component
00295       return processLeafIpFormula (tmpString);
00296     }
00297       else
00298     {
00299       // recursion takes gobs of memory on long defined strings
00300       // in part because of the 1000 bytes tmpBuf
00301       return createIpFormulaFromList (tmpString);
00302       /* 
00303          checkString = strchr( tmpString, ',' );
00304          length = checkString - tmpString;
00305          strncpy( tmpBuf, tmpString, length );
00306          tmpBuf[length] = '\0';
00307          result = processLeafIpFormula( tmpBuf );
00308          nextFormula = Rlp_ComputeIpFormulaFromString( checkString + 1 );
00309          Rlp_Formula_t *list = new_node(  Rlp_List_c, result, NIL( Rlp_Formula_t ) );
00310          list->rchild = new_node( Rlp_List_c, nextFormula, NIL( Rlp_Formula_t ) );
00311          return list; 
00312        */
00313     }
00314     }
00315 }
00316 
00317 
00318 /**
00319   * \brief Iterative code to create ip formula for a string assumed
00320   * to be of the form foo,bar.
00321   */
00322 
00323 static Rlp_Formula_t *
00324 createIpFormulaFromList (char *aString)
00325 {
00326   char *iterString = aString;
00327   Rlp_Formula_t *result =
00328     new_node (Rlp_List_c, NIL (Rlp_Formula_t), NIL (Rlp_Formula_t));
00329   Rlp_Formula_t *lastNode = result;
00330   char tmpBuf[1000];
00331   while (1)
00332     {
00333 
00334       char *commaString = strchr (iterString, ',');
00335       if (commaString == NIL (char))
00336     {
00337       lastNode->lchild = Rlp_ComputeIpFormulaFromString (iterString);
00338       return result;
00339     }
00340       int length = commaString - iterString;
00341       strncpy (tmpBuf, iterString, length);
00342       tmpBuf[length] = '\0';
00343       // had processLeafIpFormula here, but list element could be more general
00344       lastNode->lchild = Rlp_ComputeIpFormulaFromString (tmpBuf);
00345       lastNode->rchild =
00346     new_node (Rlp_List_c, NIL (Rlp_Formula_t), NIL (Rlp_Formula_t));
00347       lastNode = lastNode->rchild;
00348       iterString = commaString + 1;
00349     }
00350 }
00351 
00352 
00353 /**
00354   * \brief  Process an IP formula that's a leaf formula:
00355   * ip/mask | ip | DEFINE
00356   * 
00357   */
00358 
00359 static Rlp_Formula_t *
00360 processLeafIpFormula (char *leafString)
00361 {
00362   char tmpBuf[1000];
00363   int length;
00364   u_int32_t ip;
00365   u_int32_t mask;
00366   int maskAmount;
00367 
00368   if (strchr (leafString, '.') && strchr (leafString, '/'))
00369     {
00370       // it's of the form 192.168.1.1/24 or 192.168.1.1/255.255.255.0
00371       char *endOfIp = strchr (leafString, '/');
00372       length = endOfIp - leafString;
00373       strncpy (tmpBuf, leafString, length);
00374       tmpBuf[length] = '\0';
00375       ip = Rlp_DotToInt (tmpBuf);
00376       char *beginningOfMask = endOfIp + 1;
00377       if (!strchr (beginningOfMask, '.'))
00378     {
00379       // it's of the form 192.168.1.1/24
00380       sscanf (beginningOfMask, "%u", &maskAmount);
00381       assert (maskAmount < 33);
00382       // 192.168.1.1/24 -> we're masking the last 8 bits, 
00383       // so the mask has to have the last ( 32 - 24 ) bits set to zero
00384       mask = (~0x0) << (32 - maskAmount);
00385     }
00386       else
00387     {
00388       mask = Rlp_DotToInt (beginningOfMask);
00389     }
00390       return new_node (Rlp_IpEntry_c, (Rlp_Formula_t *) ip,
00391                (Rlp_Formula_t *) mask);
00392     }
00393   if (strchr (leafString, '.'))
00394     {
00395       // it's of the form 192.168.1.1
00396       ip = Rlp_DotToInt (leafString);
00397       mask = (~0x0);        // all 1s
00398       return new_node (Rlp_IpEntry_c, (Rlp_Formula_t *) ip,
00399                (Rlp_Formula_t *) mask);
00400     }
00401   // it's got to be a macro
00402   return new_node (Rlp_Define_c, (Rlp_Formula_t *) strdup (leafString),
00403            NIL (Rlp_Formula_t));
00404 
00405 }
00406 
00407 
00408 /**
00409   * \brief  Convert a string in dotted decimal notation to an unsigned 32 bit int
00410   * 
00411   */
00412 
00413 u_int32_t
00414 Rlp_DotToInt (char *dotString)
00415 {
00416   // dotString assumed to be of the form "123.23.12.191"
00417   int i;
00418   unsigned int ipAddress = 0;
00419 
00420   char *dupDotString = strdup (dotString);
00421   char *tmpString = dupDotString;
00422   char *freeString = dupDotString;
00423 
00424   for (i = 0; i < 4; i++)
00425     {
00426       while ((*tmpString != '.') && (*tmpString != '\0'))
00427     {
00428       tmpString++;
00429     }
00430       *tmpString = '\0';
00431       unsigned int tmpInt = atoi (dupDotString);
00432       dupDotString = &(tmpString[1]);   // go to the next 8-bit int
00433       tmpString = dupDotString;
00434       ipAddress = ipAddress * 256 + tmpInt;
00435     }
00436   free (freeString);
00437   return ipAddress;
00438 }
00439 
00440 
00441 /**
00442   \brief  Parse a raw string representing a set of ports into
00443   an Rlp_Formula_t
00444   
00445  Parse a raw string representing a set of ports into
00446  an Rlp_Formula_t.  String is supposed to be from the following
00447  grammar:
00448   
00449   <pre>
00450   !foo | 10:100  | 10: | :100 | DEFINE
00451   </pre>
00452   
00453   Note: we should not have whitespace anywhere.
00454   */
00455 
00456 
00457 Rlp_Formula_t *
00458 Rlp_ComputePortFormulaFromString (char *portString)
00459 {
00460   Rlp_Formula_t *result;
00461   int highPort;
00462   int lowPort;
00463 
00464   if (util_strequal ("any", portString))
00465     {
00466       return new_node (Rlp_Any_c, NIL (Rlp_Formula_t), NIL (Rlp_Formula_t));
00467     }
00468 
00469   char *tmpString = portString;
00470   while (*tmpString != '\0')
00471     {
00472       if (isspace (*tmpString))
00473     {
00474       assert (0);
00475     }
00476       tmpString++;
00477     }
00478 
00479   bool negFlag = false;
00480   tmpString = portString;
00481   if (*tmpString == '!')
00482     {
00483       negFlag = true;
00484       tmpString++;
00485       while (isspace (*tmpString))
00486     {
00487       tmpString++;
00488     }
00489     }
00490 
00491   bool isSinglePort = true;
00492   int i;
00493   for (i = 0; i < (int) strlen (tmpString); i++)
00494     {
00495       if (!isdigit (tmpString[i]))
00496     {
00497       // not a single port, may be range or define
00498       isSinglePort = false;
00499       break;
00500     }
00501     }
00502 
00503   if (isSinglePort == true)
00504     {
00505       sscanf (tmpString, "%d", &lowPort);
00506       highPort = lowPort;
00507       Rlp_Formula_t *singlePort =
00508     new_node (Rlp_PortRange_c, (Rlp_Formula_t *) lowPort,
00509           (Rlp_Formula_t *) highPort);
00510       if (negFlag)
00511     {
00512       result = new_node (Rlp_Negation_c, singlePort, NIL (Rlp_Formula_t));
00513     }
00514       else
00515     {
00516       result = singlePort;
00517     }
00518       return result;
00519     }
00520 
00521   int length = strlen (tmpString);
00522   if (strchr (tmpString, ':'))
00523     {
00524       // it's a range
00525       if (tmpString[0] == ':')
00526     {
00527       // it's a range of the form :1024
00528       lowPort = 0;
00529       sscanf (tmpString + 1, "%d", &highPort);
00530     }
00531       else if (tmpString[length - 1] == ':')
00532     {
00533       // it's a range of the form 1024:
00534       highPort = 65535;
00535       sscanf (tmpString, "%d", &lowPort);
00536     }
00537       else
00538     {
00539       //  it's a range of the form 6000:6006
00540       sscanf (tmpString, "%d", &lowPort);
00541       tmpString = strchr (tmpString, ':');
00542       tmpString++;
00543       sscanf (tmpString, "%d", &highPort);
00544     }
00545       Rlp_Formula_t *rangeFormula =
00546     new_node (Rlp_PortRange_c, (Rlp_Formula_t *) lowPort,
00547           (Rlp_Formula_t *) highPort);
00548       if (negFlag)
00549     {
00550       result =
00551         new_node (Rlp_Negation_c, rangeFormula, NIL (Rlp_Formula_t));
00552     }
00553       else
00554     {
00555       result = rangeFormula;
00556     }
00557     }
00558   else
00559     {
00560       // it's a define
00561       result =
00562     new_node (Rlp_Define_c, (Rlp_Formula_t *) strdup (tmpString),
00563           NIL (Rlp_Formula_t));
00564       if (negFlag)
00565     {
00566       result = new_node (Rlp_Negation_c, result, NIL (Rlp_Formula_t));
00567     }
00568     }
00569   return result;
00570 }
00571 
00572 
00573 /** \brief  Take a string that potentially starts with [ and ends with
00574   ] and return a fresh string that does not include the brackets.
00575 */
00576 
00577 static char *
00578 clearBrackets (char *text)
00579 {
00580   char *firstBracket = strchr (text, '[');
00581   if (firstBracket == NIL (char))
00582     {
00583       assert (strchr (text, ']') == NIL (char));
00584       return text;
00585     }
00586 
00587   char *lastBracket = strchr (text, ']');
00588   assert (lastBracket != NIL (char));
00589 
00590   // "[abc]0" becomes "abc0"
00591   //  012345           0123
00592   int bytesNeeded = lastBracket - firstBracket;
00593   char *result = (char *) malloc ((sizeof (char) * bytesNeeded));
00594   strncpy (result, (firstBracket + 1), (bytesNeeded - 1));
00595   result[bytesNeeded - 1] = '\0';
00596 
00597   free (text);
00598 
00599   return result;
00600 }