Azinix

evl.c

Go to the documentation of this file.
00001 /** \file evl.c
00002 
00003   \brief Rule evaluation code
00004 */
00005 
00006 #include "evl.h"
00007 
00008 /**AutomaticStart*************************************************************/
00009 
00010 /*---------------------------------------------------------------------------*/
00011 /* Static function prototypes                                                */
00012 /*---------------------------------------------------------------------------*/
00013 
00014 static int computeClassId (Evl_L4LookupTable_t * aRuleTable,
00015                Evl_L4Flow_t * aFlow);
00016 static inline bool EthEvalSameIp (Pkt_EthernetHdr_t * anEth);
00017 static int printRules (Evl_L4Manager_t * tcpMgr, array_t * rules);
00018 static inline bool EthEvalAck (Pkt_EthernetHdr_t * anEth,
00019                    Rlp_AckAttribute_t * ackAttrib);
00020 static inline bool EthEvalSample (Pkt_ProcessPkt_t * pp ,
00021                   Rlp_SampleAttribute_t * sampleAttribute);
00022 static inline bool EthEvalIf (Pkt_ProcessPkt_t * pp,
00023                   Rlp_IfAttribute_t * ifAttribute);
00024 static inline bool EthEvalSeq (Pkt_EthernetHdr_t * anEth,
00025                    Rlp_SeqAttribute_t * seqAttrib);
00026 static inline bool EthEvalFlags (Pkt_EthernetHdr_t * anEthPkt,
00027                  Rlp_FlagsAttribute_t * flagsAttribute);
00028 static inline bool EthEvalItype (Pkt_EthernetHdr_t * anEthPkt,
00029                  Rlp_ItypeAttribute_t * itypeAttrib);
00030 static inline bool EthEvalIcode (Pkt_EthernetHdr_t * anEth,
00031                  Rlp_IcodeAttribute_t * icodeAttribute);
00032 static inline bool EthEvalId (Pkt_EthernetHdr_t * anEthPkt,
00033                   Rlp_IdAttribute_t * idAttribute);
00034 static inline bool EthEvalIcmpId (Pkt_EthernetHdr_t * anEth,
00035                   Rlp_IcmpIdAttribute_t * icmpIdAttribute);
00036 static inline bool EthEvalIcmpSeqId (Pkt_EthernetHdr_t * anEth,
00037                      Rlp_IcmpSeqAttribute_t *
00038                      icmpSeqAttribute);
00039 static inline bool EthEvalIpOpts (Pkt_EthernetHdr_t * anEth,
00040                   Rlp_IpOptsAttribute_t * ipOptsAttrib);
00041 static inline bool EthEvalDsize (Pkt_EthernetHdr_t * anEthPkt,
00042                  Rlp_DsizeAttribute_t * dsizeAttrib);
00043 static inline bool EthEvalTtl (Pkt_EthernetHdr_t * anEthPkt,
00044                    Rlp_TtlAttribute_t * ttlAttrib);
00045 static inline bool EthEvalIpProto (Pkt_EthernetHdr_t * anEthPkt,
00046                    Rlp_IpProtoAttribute_t * ipProtoAttribute);
00047 static inline bool EthEvalRpc (Pkt_EthernetHdr_t * anEthPkt ,
00048                    Rlp_RpcAttribute_t * rpcAttribute );
00049 static inline bool EthEvalFrag (Pkt_EthernetHdr_t * anEthPkt,
00050                 Rlp_FragbitsAttribute_t * fragAttribute);
00051 static bool evalContentChecks (array_t * l7CheckArray, char *beginText,
00052                    char *endText);
00053 static bool evalByteTest (char *beginText, char *current, char *endText,
00054               Rlp_ByteTestCheck_t * byteTestCheck);
00055 static int computeByteJump (char *begin, char *current,
00056                 Rlp_ByteJumpCheck_t * byteJumpCheck);
00057 static bool evalContentCheck (char *beginText, char *endText,
00058                   char **lastMatchPtr, char **currentPtr,
00059                   Rlp_ContentCheck_t * contentCheck);
00060 static bool myxor (bool A, bool B);
00061 static int evalPcreCheck (char *beginText, char *endText,
00062               Rlp_PcreCheck_t * pcreCheck);
00063 static void updateL4RuleArrays (Evl_L4Manager_t * l4mgr);
00064 static void updateL3RuleArrays (Evl_Manager_t * mgr);
00065 
00066 /**AutomaticEnd***************************************************************/
00067 
00068 
00069 /** \brief  Core evaluation function - takes a flow, returns
00070   set of applicable L7 rules
00071 */
00072 
00073 int
00074 Evl_ComputeL7RuleSet (Evl_L4LookupTable_t * aRuleTable, Evl_L4Flow_t * aFlow)
00075 {
00076 
00077   if (aRuleTable == NIL (Evl_L4LookupTable_t))
00078     {
00079       return -1;
00080     }
00081 
00082   int classId = computeClassId (aRuleTable, aFlow);
00083   return classId;
00084 
00085 }
00086 
00087 
00088 /**
00089   * \brief  Core evaluation function - takes a flow, returns
00090   * array of applicable L7 rules
00091   * 
00092   */
00093 util_int_array_t *
00094 Evl_ComputeL7RuleArray (Evl_L4LookupTable_t * aRuleTable,
00095             Evl_L4Flow_t * aFlow)
00096 {
00097   if (aRuleTable == NIL (Evl_L4LookupTable_t))
00098     {
00099       return NIL (util_int_array_t);
00100     }
00101   int classId = computeClassId (aRuleTable, aFlow);
00102   util_int_array_t *result = aRuleTable->ruleArrays[classId];
00103   return result;
00104 }
00105 
00106 /**
00107   * \brief  Core evaluation function - takes a lookup table and a flow,
00108   * returns the class id applicable to the flow.
00109   * 
00110   */
00111 
00112 static int
00113 computeClassId (Evl_L4LookupTable_t * aRuleTable, Evl_L4Flow_t * aFlow)
00114 {
00115   unsigned char lookupBytes[12];
00116 
00117   lookupBytes[0] = (aFlow->destPort >> 8);
00118   lookupBytes[1] = (aFlow->destPort);
00119 
00120   lookupBytes[2] = (aFlow->srcPort >> 8);
00121   lookupBytes[3] = (aFlow->srcPort);
00122 
00123   lookupBytes[4] = (aFlow->destIp >> 24);
00124   lookupBytes[5] = (aFlow->destIp >> 16);
00125   lookupBytes[6] = (aFlow->destIp >> 8);
00126   lookupBytes[7] = (aFlow->destIp);
00127 
00128   lookupBytes[8] = (aFlow->srcIp >> 24);
00129   lookupBytes[9] = (aFlow->srcIp >> 16);
00130   lookupBytes[10] = (aFlow->srcIp >> 8);
00131   lookupBytes[11] = (aFlow->srcIp);
00132 
00133   int currentNode = 0;
00134   int i;
00135   for (i = 0; i < 12; i++)
00136     {
00137       currentNode = aRuleTable->tree[256 * currentNode + lookupBytes[i]];
00138     }
00139   return currentNode;
00140 }
00141 
00142 
00143 /**
00144   * \brief  Check if src and dest ips in an eth packet are same.
00145   * 
00146   */
00147 
00148 static inline bool
00149 EthEvalSameIp (Pkt_EthernetHdr_t * anEth)
00150 {
00151   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEth);
00152   return (ipPkt->destIp == ipPkt->sourceIp);
00153 }
00154 
00155 
00156 /**
00157   * \brief  Given an ethernet packet and Evl_Manager_t encoding
00158   * a set of rules, determine all rules applicable to the packet.
00159   *
00160   * Packet is assumed to be in host order. Caller must
00161   * pass in the array_t into which results are written.
00162   * 
00163   * Not handling icmp, just tcp, udp, ip
00164   */
00165 
00166 void
00167 Evl_ComputeRuleSetForEth (Pkt_ProcessPkt_t * pp, Evl_Manager_t * globalMgr)
00168 {
00169   Pkt_EthernetHdr_t *anEthPkt = pp->pkt;
00170   array_t *result = pp->applicableRules;
00171 
00172   updateL3RuleArrays (globalMgr);
00173 
00174   array_t *genericResult = globalMgr->genericResult;
00175   array_t *layer3Result = globalMgr->layer3Result;
00176   array_t *layer4Result = globalMgr->layer4Result;
00177 
00178 
00179   if (globalMgr->genericMgr != NIL (Evl_GenericManager_t))
00180     {
00181       Evl_GenericManager_t *genericMgr = globalMgr->genericMgr;
00182       int i;
00183       for (i = 0; i < array_n (genericMgr->tcpIdToGlobalId); i++)
00184     {
00185       int id = array_fetch (int, genericMgr->tcpIdToGlobalId, i);
00186       Rlp_Formula_t *rlpFormula =
00187         array_fetch (Rlp_Formula_t *, genericMgr->L7RuleArray, i);
00188       if (Evl_EthEvalL7Rule (pp, rlpFormula, NIL (array_t)))
00189         {
00190           array_insert_last (int, genericResult, id);
00191         }
00192     }
00193     }
00194   // Evl_EvalRuleArray( l4mgr, pp, potentialRulesFromFsm, NIL(util_int_array_t), rulesFromFsm );
00195 
00196   if ((Pkt_EthernetReadL3Type (anEthPkt) == Pkt_L3ProtIp_c))
00197     {
00198       Evl_L4ComputeRuleSetForEth (pp, globalMgr->ipMgr, layer3Result);
00199     }
00200   else
00201     {
00202       // do nothing - we have no non ip rules
00203     }
00204 
00205   if ((Pkt_EthernetReadL3Type (anEthPkt) == Pkt_L3ProtIp_c))
00206     {
00207       Pkt_IpHdr_t *anIpPkt = Pkt_EthernetExtractIp (anEthPkt);
00208 
00209       u_int8_t layer4Prot = anIpPkt->protocol;
00210 
00211       if (layer4Prot == Pkt_L4ProtIcmp_c)
00212     {
00213       Evl_L4ComputeRuleSetForEth (pp, globalMgr->icmpMgr, layer4Result);
00214     }
00215       else if (layer4Prot == Pkt_L4ProtTcp_c)
00216     {
00217       Evl_L4ComputeRuleSetForEth (pp, globalMgr->tcpMgr, layer4Result);
00218     }
00219       else if (layer4Prot == Pkt_L4ProtUdp_c)
00220     {
00221       Evl_L4ComputeRuleSetForEth (pp, globalMgr->udpMgr, layer4Result);
00222     }
00223       else
00224     {
00225       // only handling tcp/icmp/udp layer 4 protocols right now
00226       // so do nothing
00227     }
00228     }
00229 
00230   array_merge (result, genericResult, layer3Result, layer4Result);
00231 
00232   return;
00233 }
00234 
00235 
00236 /**
00237   * \brief Compute rules for an ip packet based on the L4 structure.
00238   *
00239   * This only works  for certain l4 protocols, such as tcp, udp, icmp
00240   * (Currently, we use it for ip too)
00241   */
00242 
00243 void
00244 Evl_L4ComputeRuleSetForEth (Pkt_ProcessPkt_t * pp,
00245                 Evl_L4Manager_t * l4mgr, array_t * result)
00246 {
00247   Pkt_EthernetHdr_t *anEthPkt = pp->pkt;
00248 
00249   updateL4RuleArrays (l4mgr);
00250 
00251   array_t *potentialRulesFromFsm = l4mgr->potentialRulesFromFsm;
00252   array_t *rulesFromFsm = l4mgr->rulesFromFsm;
00253   array_t *rulesFromShortStringTable = l4mgr->rulesFromShortStringTable;
00254   array_t *rulesFromNoContentTable = l4mgr->rulesFromNoContentTable;
00255 
00256 
00257   Pkt_IpHdr_t *anIpPkt = Pkt_EthernetExtractIp (anEthPkt);
00258 
00259   Evl_L4Flow_t ipFlow;
00260   char *payload;
00261   int length = anIpPkt->length;
00262   int payloadLength;
00263 
00264   ipFlow.srcIp = anIpPkt->sourceIp;
00265   ipFlow.destIp = anIpPkt->destIp;
00266 
00267   if (anIpPkt->protocol == Pkt_L4ProtTcp_c)
00268     {               // tcp == 6
00269       Pkt_TcpHdr_t *aTcpPkt = Pkt_IpExtractTcp (anIpPkt);
00270       ipFlow.srcPort = aTcpPkt->srcPort;
00271       ipFlow.destPort = aTcpPkt->destPort;
00272       payload = Pkt_TcpHdrReadPayload (aTcpPkt);
00273       payloadLength = length - (payload - ((char *) anIpPkt));
00274     }
00275   else if (anIpPkt->protocol == Pkt_L4ProtUdp_c)
00276     {               // udp == 17
00277       Pkt_UdpHdr_t *aUdpPkt = Pkt_IpExtractUdp (anIpPkt);
00278       ipFlow.srcPort = aUdpPkt->srcPort;
00279       ipFlow.destPort = aUdpPkt->destPort;
00280       payload = Pkt_UdpHdrReadPayload (aUdpPkt);
00281       payloadLength = length - (payload - ((char *) anIpPkt));
00282     }
00283   else
00284     {
00285       // it's a generic ip pkt, doesn't really matter if it's icmp,
00286       // since the detailed checks Eth_EvalRuleArray will get them
00287       // there (should) be no dependence on port numbers so we just
00288       // set ports to 0
00289       ipFlow.srcPort = 0;
00290       ipFlow.destPort = 0;
00291       // there should be no content checks,  but the following will
00292       // look from the end of the ip layer to the end of the packet
00293       // ie it treats the l4 component as payload
00294       payload = ((char *) anIpPkt) + length;
00295       payloadLength = length;
00296     }
00297 
00298   int rulesFromDestPortTableIndex =
00299     Evl_ComputeL7RuleSet (l4mgr->destPortRuleTable, &ipFlow);
00300   var_set_t *rulesFromDestPortTable =
00301     (rulesFromDestPortTableIndex ==
00302      -1) ? NIL (var_set_t) : l4mgr->destPortRuleTable->
00303     ruleSets[rulesFromDestPortTableIndex];
00304 
00305   int rulesFromSrcPortTableIndex =
00306     Evl_ComputeL7RuleSet (l4mgr->srcPortRuleTable, &ipFlow);
00307   var_set_t *rulesFromSrcPortTable =
00308     (rulesFromSrcPortTableIndex ==
00309      -1) ? NIL (var_set_t) : l4mgr->srcPortRuleTable->
00310     ruleSets[rulesFromSrcPortTableIndex];
00311 
00312   int rulesFromNoPortTableIndex =
00313     Evl_ComputeL7RuleSet (l4mgr->noPortRuleTable, &ipFlow);
00314   var_set_t *rulesFromNoPortTable =
00315     (rulesFromNoPortTableIndex ==
00316      -1) ? NIL (var_set_t) : l4mgr->noPortRuleTable->
00317     ruleSets[rulesFromNoPortTableIndex];
00318 
00319   // short circuit eval seems to fail, hence the
00320   // nested grouping
00321   if (((rulesFromDestPortTable) == NIL (var_set_t)
00322        || (var_set_is_empty (rulesFromDestPortTable))))
00323     {
00324       if (((rulesFromSrcPortTable) == NIL (var_set_t)
00325        || (var_set_is_empty (rulesFromSrcPortTable))))
00326     {
00327       if ((rulesFromNoPortTable) == NIL (var_set_t)
00328           || (var_set_is_empty (rulesFromNoPortTable)))
00329         {
00330           /// \todo check that nil is acceptable return
00331           return;       
00332         }
00333     }
00334     }
00335 
00336   // if there are no states, just skip this check
00337   if (l4mgr->fsm->N != 0)
00338     {
00339       Evl_FsmComputeRules (l4mgr->fsm,
00340                l4mgr->cm->stringToId,
00341                l4mgr->cm->idToRules,
00342                rulesFromDestPortTable,
00343                rulesFromSrcPortTable,
00344                rulesFromNoPortTable,
00345                payload, payloadLength, potentialRulesFromFsm);
00346     }
00347 
00348   Evl_EvalRuleArray (l4mgr, pp, potentialRulesFromFsm, NIL (util_int_array_t),
00349              rulesFromFsm);
00350 
00351   util_int_array_t *potentialRulesFromShortStringTable =
00352     Evl_ComputeL7RuleArray (l4mgr->shortStringRuleTable, &ipFlow);
00353 
00354   Evl_EvalRuleArray (l4mgr, pp, NIL (array_t),
00355              potentialRulesFromShortStringTable,
00356              rulesFromShortStringTable);
00357 
00358   util_int_array_t *potentialRulesFromNoContentTable =
00359     Evl_ComputeL7RuleArray (l4mgr->noContentCheckTable, &ipFlow);
00360 
00361   Evl_EvalRuleArray (l4mgr, pp, NIL (array_t),
00362              potentialRulesFromNoContentTable,
00363              rulesFromNoContentTable);
00364 
00365   array_merge (result,
00366            rulesFromFsm,
00367            rulesFromShortStringTable, rulesFromNoContentTable);
00368 
00369   return;
00370 }
00371 
00372 
00373 /**
00374   * \brief  Print the set of rules given by an array
00375   */
00376 
00377 static int
00378 printRules (Evl_L4Manager_t * tcpMgr, array_t * rules)
00379 {
00380   if (rules == NIL (array_t))
00381     {
00382       printf ("No applicable rules\n");
00383       return 0;
00384     }
00385   printf ("Applicable rules:\n");
00386   int i;
00387   for (i = 0; i < array_n (rules); i++)
00388     {
00389       int id = array_fetch (int, rules, i);
00390       int globalId = array_fetch (int, tcpMgr->tcpIdToGlobalId, id);
00391       char *text = array_fetch (char *, tcpMgr->mgr->rawRules, globalId);
00392       printf ("Rule %s\n", text);
00393     }
00394   return 0;
00395 }
00396 
00397 
00398 /** \brief  Check content of an Eth packet.
00399   aL7CheckArray is an array of Rlp_L7Check_t *
00400 */
00401 
00402 int
00403 Evl_EthEvalL7RuleContentCheck (Pkt_EthernetHdr_t * anEth,
00404                    array_t * aL7CheckArray)
00405 {
00406   Pkt_IpHdr_t *anIp = Pkt_EthernetExtractIp (anEth);
00407 
00408   char *textEnd = ((char *) anIp) + anIp->length;
00409   char *textStart;
00410 
00411   /// \todo change magic numbers
00412   if (anIp->protocol == 1)
00413     {
00414       // icmp packet
00415       Pkt_IcmpHdr_t *anIcmp = Pkt_IpExtractIcmp (anIp);
00416       textStart = ((char *) anIcmp) + sizeof (Pkt_IcmpHdr_t);
00417     }
00418   else if (anIp->protocol == 6)
00419     {
00420       // tcp packet
00421       Pkt_TcpHdr_t *aTcp = Pkt_IpExtractTcp (anIp);
00422       textStart = ((char *) aTcp) + 4 * aTcp->doff;
00423     }
00424   else if (anIp->protocol == 17)
00425     {
00426       // udp packet
00427       Pkt_UdpHdr_t *aUdp = Pkt_IpExtractUdp (anIp);
00428       textStart = ((char *) aUdp) + sizeof (Pkt_UdpHdr_t);
00429     }
00430   else
00431     {
00432       printf ("Unknown layer 4 protocol, bailing\n");
00433       // rather than crash, we circumvent content checks
00434       textStart = textEnd;
00435     }
00436 
00437   bool result = evalContentChecks (aL7CheckArray, textStart, textEnd);
00438 
00439   return result;
00440 }
00441 
00442 
00443 /** \brief  Check the tcp ack field on an ethernet packet */
00444 
00445 static inline bool
00446 EthEvalAck (Pkt_EthernetHdr_t * anEth, Rlp_AckAttribute_t * ackAttrib)
00447 {
00448   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEth);
00449   if (ipPkt->protocol != 6)
00450     {
00451       return true;      // defaults to true, since it's not an TCP pkt
00452     }
00453   Pkt_TcpHdr_t *tcpPkt = Pkt_IpExtractTcp (ipPkt);
00454 
00455   return (tcpPkt->ackNum == ackAttrib->ackValue);
00456 }
00457 
00458 
00459 /** \brief  Check  if we are to sample this entry.  */
00460 
00461 static inline bool
00462 EthEvalSample (Pkt_ProcessPkt_t * pp ,
00463            Rlp_SampleAttribute_t * sampleAttribute)
00464 {
00465   double threshold = sampleAttribute->threshold;
00466 
00467   double trial = util_unit_rand ();
00468 
00469   if (trial < threshold)
00470     {
00471       return 1;
00472     }
00473   else
00474     {
00475       return 0;
00476     }
00477 }
00478 
00479 
00480 /** \brief  Check the originating interface */
00481 
00482 static inline bool
00483 EthEvalIf (Pkt_ProcessPkt_t * pp, Rlp_IfAttribute_t * ifAttribute)
00484 {
00485   if (pp->inIf == NIL (Pkt_LibPcap_t))
00486     {
00487       // assuming that this is from synthetic traffic, so
00488       // return true
00489       return 1;
00490     }
00491 
00492   if (ifAttribute->interface != NIL (Pkt_LibPcap_t))
00493     {
00494       return (ifAttribute->interface == pp->inIf);
00495     }
00496   // ifAttribute->if has not been set, let's see if
00497   // we can set it now
00498   if (util_strequal (pp->inIf->interfaceName, ifAttribute->ifName))
00499     {
00500       // we have a match, so let's set the if field
00501       ifAttribute->interface = pp->inIf;
00502       return 1;
00503     }
00504   else
00505     {
00506       // we can't set ifAttribute->if, since we didn't have a match
00507       return 0;
00508     }
00509 }
00510 
00511 
00512 /**
00513   * \brief  Check the tcp seq field on an ethernet packet 
00514   * 
00515   * No check to see if the eth packet is infact a tcp packet.
00516   * 
00517   */
00518 
00519 static inline bool
00520 EthEvalSeq (Pkt_EthernetHdr_t * anEth, Rlp_SeqAttribute_t * seqAttrib)
00521 {
00522   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEth);
00523   Pkt_TcpHdr_t *tcpPkt = Pkt_IpExtractTcp (ipPkt);
00524 
00525   return (tcpPkt->seqNum == seqAttrib->seqValue);
00526 }
00527 
00528 
00529 /**
00530   * \brief  Check tcp flags
00531   * 
00532   * Do not see if packet is actually a tcp packet
00533   * 
00534   */
00535 
00536 static inline bool
00537 EthEvalFlags (Pkt_EthernetHdr_t * anEthPkt,
00538           Rlp_FlagsAttribute_t * flagsAttribute)
00539 {
00540   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00541   Pkt_TcpHdr_t *tcpPkt = Pkt_IpExtractTcp (ipPkt);
00542 
00543   if (flagsAttribute->F != X_c)
00544     if (tcpPkt->fin != flagsAttribute->F)
00545       return false;
00546 
00547   if (flagsAttribute->S != X_c)
00548     if (tcpPkt->syn != flagsAttribute->S)
00549       return false;
00550 
00551   if (flagsAttribute->R != X_c)
00552     if (tcpPkt->rst != flagsAttribute->R)
00553       return false;
00554 
00555   if (flagsAttribute->P != X_c)
00556     if (tcpPkt->psh != flagsAttribute->P)
00557       return false;
00558 
00559   if (flagsAttribute->A != X_c)
00560     if (tcpPkt->ack != flagsAttribute->A)
00561       return false;
00562 
00563   if (flagsAttribute->U != X_c)
00564     if (tcpPkt->urg != flagsAttribute->U)
00565       return false;
00566 
00567   // not sure about the order or the meaning of the next two
00568   // related to cong window resizing and explicit congestion notification
00569   if (flagsAttribute->r_2 != X_c)
00570     if (tcpPkt->ece != flagsAttribute->r_2)
00571       return false;
00572 
00573   if (flagsAttribute->r_1 != X_c)
00574     if (tcpPkt->cwr != flagsAttribute->r_1)
00575       return false;
00576 
00577   return true;
00578 }
00579 
00580 
00581 /**
00582   * \brief  Check the type field in an ICMP packet encapsulated
00583   * in an ethernet frame.
00584   */
00585 
00586 static inline bool
00587 EthEvalItype (Pkt_EthernetHdr_t * anEthPkt,
00588           Rlp_ItypeAttribute_t * itypeAttrib)
00589 {
00590   Pkt_IcmpHdr_t *icmpPkt = Pkt_EthernetExtractIcmp (anEthPkt);
00591 
00592   return (icmpPkt != NIL (Pkt_IcmpHdr_t)
00593       && icmpPkt->type == itypeAttrib->itype);
00594 }
00595 
00596 
00597 /**
00598   * \brief  Check the icmp code value on an ethernet packet, assumed
00599   * to encapsulate an icmp packet
00600   */
00601 
00602 static inline bool
00603 EthEvalIcode (Pkt_EthernetHdr_t * anEth,
00604           Rlp_IcodeAttribute_t * icodeAttribute)
00605 {
00606   Pkt_IcmpHdr_t *icmpPkt = Pkt_EthernetExtractIcmp (anEth);
00607 
00608   return (icmpPkt->code == icodeAttribute->icode);
00609 }
00610 
00611 
00612 /**
00613   * \brief  Check the ip id value on an ethernet packet, assumed
00614   * to encapsulate an ip packet
00615   * 
00616   */
00617 
00618 static inline bool
00619 EthEvalId (Pkt_EthernetHdr_t * anEthPkt, Rlp_IdAttribute_t * idAttribute)
00620 {
00621   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00622   int protId = idAttribute->value;
00623   int pktId = ipPkt->id;
00624   if (idAttribute->lessThan)
00625     {
00626       return (pktId < protId);
00627     }
00628   else if (idAttribute->greaterThan)
00629     {
00630       return (pktId > protId);
00631     }
00632   else if (idAttribute->negated)
00633     {
00634       return (pktId != protId);
00635     }
00636   else
00637     {
00638       return (pktId == pktId);
00639     }
00640 }
00641 
00642 
00643 /**
00644   * \brief  Check the icmp id on an ethernet packet, assumed
00645   * to encapsulate an icmp packet
00646   * 
00647   */
00648 
00649 static inline bool
00650 EthEvalIcmpId (Pkt_EthernetHdr_t * anEth,
00651            Rlp_IcmpIdAttribute_t * icmpIdAttribute)
00652 {
00653   Pkt_IcmpHdr_t *icmpPkt = Pkt_EthernetExtractIcmp (anEth);
00654 
00655   return (icmpPkt->un.echo.id == icmpIdAttribute->icmpId);
00656 }
00657 
00658 
00659 /**
00660   * \brief  Check the icmp seq value on an ethernet packet, assumed
00661   * to encapsulate an icmp packet
00662   */
00663 
00664 static inline bool
00665 EthEvalIcmpSeqId (Pkt_EthernetHdr_t * anEth,
00666           Rlp_IcmpSeqAttribute_t * icmpSeqAttribute)
00667 {
00668   Pkt_IcmpHdr_t *icmpPkt = Pkt_EthernetExtractIcmp (anEth);
00669 
00670   return (icmpPkt->un.echo.sequence == icmpSeqAttribute->seqValue);
00671 }
00672 
00673 
00674 /**
00675   * \brief  Check the ipopts field on the ip packet encapsulated by
00676   * an ethernet packet
00677   * 
00678   * Options are rare, but we have to support them.
00679   * 
00680   */
00681 
00682 static inline bool
00683 EthEvalIpOpts (Pkt_EthernetHdr_t * anEth,
00684            Rlp_IpOptsAttribute_t * ipOptsAttrib)
00685 {
00686 
00687   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEth);
00688 
00689   int headerLength = ipPkt->ihl * 4;    // the header length is in multiples of
00690   // 4 bytes
00691 
00692   /* test for IP options */
00693   int ipOptionsLen = headerLength - sizeof (Pkt_IpHdr_t);
00694   if (ipOptionsLen == 0)
00695     {
00696       // no options so we can just return false, there's no match on
00697       // the options field
00698       return false;
00699     }
00700 
00701   char *options = ((char *) ipPkt) + sizeof (Pkt_IpHdr_t);
00702 
00703   // we walk down the array of options, taking care to advance
00704   // the pointer appropriately because of the following:
00705 
00706   //    "Options 0 and 1 are exactly one
00707   //    octet which is their type field.  All other options have their one
00708   //    octet type field, followed by a one octet length field, followed by
00709   //    length-2 octets of option data."  
00710 
00711   int i;
00712   for (i = 0; i < ipOptionsLen; /* increment appropriately in loop */ )
00713     {
00714       u_int8_t type = options[i];
00715       if (type == 0)
00716     {
00717       // it's eol
00718       if (ipOptsAttrib->ipOpt == Rlp_eol_c)
00719         {
00720           return true;
00721         }
00722       else
00723         {
00724           i = i + 1;    // the eol field is just one byte, the type
00725         }
00726     }
00727       if (type == 1)
00728     {
00729       // it's nop
00730       if (ipOptsAttrib->ipOpt == Rlp_nop_c)
00731         {
00732           return true;
00733         }
00734       else
00735         {
00736           i = i + 1;    // the eol field is just one byte, the type
00737         }
00738     }
00739       if (type == 7)
00740     {
00741       // it's rr
00742       if (ipOptsAttrib->ipOpt == Rlp_rr_c)
00743         {
00744           return true;
00745         }
00746       else
00747         {
00748           i = i + 4;
00749         }
00750     }
00751       if (type == 68)
00752     {
00753       // it's ts
00754       if (ipOptsAttrib->ipOpt == Rlp_ts_c)
00755         {
00756           return true;
00757         }
00758       else
00759         {
00760           i = i + 4;
00761         }
00762     }
00763       if (type == 130)
00764     {
00765       // it's sec
00766       if (ipOptsAttrib->ipOpt == Rlp_sec_c)
00767         {
00768           return true;
00769         }
00770       else
00771         {
00772           i = i + 4;
00773         }
00774     }
00775       if (type == 131)
00776     {
00777       // it's lsrr
00778       if (ipOptsAttrib->ipOpt == Rlp_lsrr_c)
00779         {
00780           return true;
00781         }
00782       else
00783         {
00784           i = i + 4;
00785         }
00786     }
00787       if (type == 137)
00788     {
00789       // it's ssrr
00790       if (ipOptsAttrib->ipOpt == Rlp_ssrr_c)
00791         {
00792           return true;
00793         }
00794       else
00795         {
00796           i = i + 4;
00797         }
00798     }
00799       if (type == 136)
00800     {
00801       // it's stream id
00802       if (ipOptsAttrib->ipOpt == Rlp_satid_c)
00803         {
00804           return true;
00805         }
00806       else
00807         {
00808           i = i + 4;
00809         }
00810     }
00811       // if we hit an unrecognized option, we'll stay in the loop forever,
00812       // unles we do something - so we jsut return true
00813 
00814       /// \todo Understand exactly what the desired behavior should be
00815       if (!
00816       ((type == 0) || (type == 1) || (type == 7) || (type == 68)
00817        || (type == 130) || (type == 131) || (type == 137)
00818        || (type == 136)))
00819     {
00820       return true;
00821     }
00822     }
00823   return false;
00824 }
00825 
00826 
00827 /**
00828   * \brief  Check the dsize field on a packet
00829   */
00830 
00831 static inline bool
00832 EthEvalDsize (Pkt_EthernetHdr_t * anEthPkt,
00833           Rlp_DsizeAttribute_t * dsizeAttrib)
00834 {
00835   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00836 
00837   if (dsizeAttrib->greaterThan)
00838     {
00839       return (ipPkt->length > dsizeAttrib->dsize);
00840     }
00841   if (dsizeAttrib->lessThan)
00842     {
00843       return (ipPkt->length < dsizeAttrib->dsize);
00844     }
00845   return (ipPkt->length == dsizeAttrib->dsize);
00846 }
00847 
00848 
00849 /**
00850   * \brief  Check the Ttl field on a packet
00851   */
00852 
00853 static inline bool
00854 EthEvalTtl (Pkt_EthernetHdr_t * anEthPkt, Rlp_TtlAttribute_t * ttlAttrib)
00855 {
00856   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00857 
00858   if (ttlAttrib->greaterThan)
00859     {
00860       return (ipPkt->TTL > ttlAttrib->ttl);
00861     }
00862   if (ttlAttrib->lessThan)
00863     {
00864       return (ipPkt->TTL < ttlAttrib->ttl);
00865     }
00866   return (ipPkt->TTL == ttlAttrib->ttl);
00867 }
00868 
00869 
00870 /**
00871   * \brief  Check proto field
00872   * 
00873   */
00874 
00875 static inline bool
00876 EthEvalIpProto (Pkt_EthernetHdr_t * anEthPkt,
00877         Rlp_IpProtoAttribute_t * ipProtoAttribute)
00878 {
00879   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00880   int ruleProt = ipProtoAttribute->value;
00881   int pktProt = ipPkt->protocol;
00882   if (ipProtoAttribute->lessThan)
00883     {
00884       return (pktProt < ruleProt);
00885     }
00886   else if (ipProtoAttribute->greaterThan)
00887     {
00888       return (pktProt > ruleProt);
00889     }
00890   else if (ipProtoAttribute->negated)
00891     {
00892       return (pktProt != ruleProt);
00893     }
00894   else
00895     {
00896       return (ruleProt == pktProt);
00897     }
00898 }
00899 
00900 
00901 /**
00902   * \brief  Implement RPC checks
00903   * 
00904   * Peterson and Davie 
00905   * talk about these in Computer Networks, 2nd edition,
00906   * but the packet format is unclear.
00907   * 
00908   * There are very few rules with RPC checks.
00909   */
00910 
00911 static inline bool
00912 EthEvalRpc (Pkt_EthernetHdr_t * anEthPkt ,
00913         Rlp_RpcAttribute_t * rpcAttribute )
00914 {
00915   printf ("Have not implemented RPC checks, returning fails\n");
00916   return 0;
00917 }
00918 
00919 
00920 /**
00921   * \brief  Check frag bits
00922   * 
00923   * Do not see if packet is actually an ip packet
00924   * 
00925   */
00926 
00927 static inline bool
00928 EthEvalFrag (Pkt_EthernetHdr_t * anEthPkt,
00929          Rlp_FragbitsAttribute_t * fragAttribute)
00930 {
00931   Pkt_IpHdr_t *ipPkt = Pkt_EthernetExtractIp (anEthPkt);
00932 
00933   if (fragAttribute->MF != X_c)
00934     {
00935       if (ipPkt->MF != fragAttribute->MF)
00936     {
00937       return false;
00938     }
00939     }
00940   if (fragAttribute->DF != X_c)
00941     {
00942       if (ipPkt->DF != fragAttribute->DF)
00943     {
00944       return false;
00945     }
00946     }
00947   if (fragAttribute->RB != X_c)
00948     {
00949       if (ipPkt->RB != fragAttribute->RB)
00950     {
00951       return false;
00952     }
00953     }
00954   return true;
00955 
00956 };
00957 
00958 
00959 /**
00960   * \brief  Given an array_t or util_int_array_t of rules, return the subset that is applicable of
00961   * the given packet.
00962   * 
00963   * Result must be passed in, and be as long as there
00964   * are rules in the mgr.
00965   * 
00966   */
00967 
00968 void
00969 Evl_EvalRuleArray (Evl_L4Manager_t * mgr,
00970            Pkt_ProcessPkt_t * pp,
00971            array_t * ruleArray,
00972            util_int_array_t * ruleIntArray, array_t * result)
00973 {
00974   int arrayLength;
00975   int index;
00976   int i;
00977 
00978   if (ruleArray != NIL (array_t))
00979     {
00980       arrayLength = array_n (ruleArray);
00981     }
00982   else if (ruleIntArray != NIL (util_int_array_t))
00983     {
00984       arrayLength = ruleIntArray->length;
00985     }
00986   else
00987     {
00988       return;
00989     }
00990 
00991   for (i = 0; i < arrayLength; i++)
00992     {
00993       if (ruleArray)
00994     {
00995       index = array_fetch (int, ruleArray, i);
00996     }
00997       else
00998     {
00999       index = ruleIntArray->entries[i];
01000     }
01001       Rlp_Formula_t *rlpFormula =
01002     array_fetch (Rlp_Formula_t *, mgr->L7RuleArray, index);
01003       array_t *l7CheckArray =
01004     array_fetch (array_t *, mgr->contentChecks, index);
01005       if (Evl_EthEvalL7Rule (pp, rlpFormula, l7CheckArray))
01006     {
01007       /** \todo confirm fix
01008       was inserting index, but should have converted it to the index
01009       from the global manager
01010       */
01011       // before: array_insert_last( int, result, index ); 
01012       int globalIndex = array_fetch (int, mgr->tcpIdToGlobalId, index);
01013 
01014       array_insert_last (int, result, globalIndex);
01015     }
01016     }
01017   return;
01018 }
01019 
01020 
01021 /**
01022   * \brief  Given text, defined by beginning and end pointers, and
01023   * an array of content checks, determine if the content
01024   * checks hold of the text.
01025   * 
01026   */
01027 
01028 static bool
01029 evalContentChecks (array_t * l7CheckArray, char *beginText, char *endText)
01030 {
01031   char *lastMatch = beginText;
01032   char *current = beginText;
01033   int i;
01034   for (i = 0; i < array_n (l7CheckArray); i++)
01035     {
01036       Rlp_L7Check_t *aCheck = array_fetch (Rlp_L7Check_t *, l7CheckArray, i);
01037       if (aCheck->type == Rlp_L7ByteTestCheck_c)
01038     {
01039       if (!evalByteTest
01040           (beginText, current, endText, aCheck->entryData.byteTestCheck))
01041         {
01042           return false;
01043         }
01044       else
01045         {
01046           continue;
01047         }
01048     }
01049       else if (aCheck->type == Rlp_L7ByteJumpCheck_c)
01050     {
01051       current +=
01052         computeByteJump (beginText, current,
01053                  aCheck->entryData.byteJumpCheck);
01054       assert (current <= endText);  // not sure what's supposed to happen 
01055       // if the byte jump takes us past endText
01056       continue;
01057     }
01058       else if ((aCheck->type == Rlp_L7ContentCheck_c) ||
01059            (aCheck->type == Rlp_L7UriContentCheck_c))
01060     {
01061       // the evalContentCheck routine is responsible for updating the 
01062       // last match pointer and the current pointer
01063       if (!evalContentCheck
01064           (beginText, endText, &lastMatch, &current,
01065            aCheck->entryData.contentCheck))
01066         {
01067           return false;
01068         }
01069     }
01070       else
01071     {
01072       assert (aCheck->type == Rlp_L7PcreCheck_c);
01073       if (!evalPcreCheck
01074           (beginText, endText, aCheck->entryData.pcreCheck))
01075         {
01076           return false;
01077         }
01078     }
01079     }
01080   // all checks were met for us to get here, ergo
01081   // the check is true
01082   return true;
01083 }
01084 
01085 
01086 /**
01087     \brief  Given some text, check to see if the byte-test holds
01088     
01089     Given some text, check to see if the byte-test holds.
01090     
01091     The byte test structure is as follows:
01092   
01093 <pre>
01094     struct Rlp_ByteTestStruct {
01095     int bytesToConvert;
01096     char check; // can be one of '<' , '<' , '=' , '!'
01097     int value; // value to test the converted value against
01098     int offset; // number of bytes into the payload to being processing
01099     bool relative; // use an offset relative to the last pattern match
01100     bool useLittleEndian; // default is big endian
01101     bool isString; // data is stored in string packet format
01102     bool isHex; // converted string data is represented in hex
01103     bool isDec; // converted string data is represented in decimal
01104     bool isOct; // converted string data is represented in oct
01105     };
01106     
01107     complete set of checks:
01108     
01109     byte_test:1,>,6,2
01110     byte_test:1,>,7,1
01111     byte_test:2,>,1024,0,relative,little
01112     byte_test:4,>,100,20,relative
01113     byte_test:4,>,1000,28,relative
01114     byte_test:4,>,1024,20,relative
01115     byte_test:4,>,128,20,relative
01116     byte_test:4,>,128,8,relative
01117     byte_test:4,>,512,16,relative
01118     byte_test:4,>,512,240,relative
01119     byte_test:5,>,256,0,string,dec,relative
01120 </pre>
01121     
01122 */
01123 
01124 static bool
01125 evalByteTest (char *beginText,
01126           char *current,
01127           char *endText, Rlp_ByteTestCheck_t * byteTestCheck)
01128 {
01129   char *convertTextFromHere;
01130   if (byteTestCheck->relative)
01131     {
01132       convertTextFromHere = current + byteTestCheck->offset;
01133     }
01134   else
01135     {
01136       convertTextFromHere = beginText + byteTestCheck->offset;
01137     }
01138   char tmpBuf[100];
01139   assert (byteTestCheck->bytesToConvert < 100);
01140   /** \todo need to figure out how to handle the useLittleEndian flag
01141   since default is big endian, and our machine is little endian
01142   for now we're ignoring this issue, will have to fix it
01143   */
01144   memcpy (tmpBuf, convertTextFromHere, byteTestCheck->bytesToConvert);
01145   tmpBuf[byteTestCheck->bytesToConvert] = '\0';
01146 
01147   int value;
01148   sscanf (tmpBuf, "%d", &value);
01149   if (byteTestCheck->check == '=')
01150     {
01151       return (value == byteTestCheck->value);
01152     }
01153   else if (byteTestCheck->check == '>')
01154     {
01155       return (value > byteTestCheck->value);
01156     }
01157   else if (byteTestCheck->check == '<')
01158     {
01159       return (value < byteTestCheck->value);
01160     }
01161   else
01162     {
01163       // unclear what ! means in the manual, and it's never used
01164       printf ("Unknown type of byteTestCheck operator: %c\n",
01165           byteTestCheck->check );
01166       assert (0);
01167     }
01168 
01169   // unreachable code
01170   assert (0);
01171   return false;
01172 }
01173 
01174 
01175 /**
01176   \brief  Compute the number of bytes to advance the current pointer by.
01177   
01178   *All uses: 
01179   
01180   <pre>
01181   byte_jump:4,12,relative,align
01182   byte_jump:4,20,relative,align
01183   byte_jump:4,4,relative,align
01184   </pre>
01185    
01186   Format
01187   
01188   byte_jump: <bytes_to_convert>, <offset> \
01189   [, [relative],[big],[little],[string],[hex],[dec],[oct],[align]]
01190   
01191 */
01192 
01193 static int
01194 computeByteJump (char *begin,
01195          char *current, Rlp_ByteJumpCheck_t * byteJumpCheck)
01196 {
01197   char *start;
01198   int jumpAmount;
01199 
01200   if (byteJumpCheck->relative)
01201     {
01202       start = current;
01203     }
01204   else
01205     {
01206       start = begin;
01207     }
01208 
01209   start += byteJumpCheck->offset;
01210   if (byteJumpCheck->doAlign)
01211     {
01212       if ((((u_int32_t) start) & 0x3) == 0x0)
01213     {
01214       // already aligned, do nothing
01215     }
01216       else
01217     {
01218       // set the 2 lsb bits to 0, and add 4
01219       start = (char *) (((((u_int32_t) start) & (~(u_int32_t) 0x3))) + 4);
01220     }
01221     }
01222 
01223   char tmpBuf[100];
01224 
01225   assert (byteJumpCheck->bytesToConvert < 100);
01226   memcpy (tmpBuf, start, byteJumpCheck->bytesToConvert);
01227   tmpBuf[byteJumpCheck->bytesToConvert] = '\0';
01228   sscanf (tmpBuf, "%d", &jumpAmount);
01229 
01230   assert (jumpAmount >= 0);
01231   assert (jumpAmount <= 65536); // sanity check, largest ip packet
01232 
01233   return jumpAmount;
01234 }
01235 
01236 
01237 /** \brief Trivial function implementing logic xor, cleans up logic below */
01238 
01239 static bool
01240 myxor (bool A, bool B)
01241 {
01242   if ((A && B) || ((!A) && (!B)))
01243     {
01244       return false;
01245     }
01246   return true;
01247 }
01248 
01249 
01250 /**
01251   * \brief  Perform core content check
01252   * 
01253   */
01254 
01255 static bool
01256 evalContentCheck (char *beginText,
01257           char *endText,
01258           char **lastMatchPtr,
01259           char **currentPtr, Rlp_ContentCheck_t * contentCheck)
01260 {
01261   /// \todo Ignoring case for now.
01262 
01263   char *current = *currentPtr;
01264   char *tightEndText;
01265 
01266   if (contentCheck->offset != -1)
01267     {
01268       // it's a local variable, so we can change it safely
01269       beginText = beginText + contentCheck->offset;
01270     }
01271   if (contentCheck->depth != -1)
01272     {
01273       // it's a local variable, so we can change it safely
01274       // depth is from beginning, so we add it to begin text
01275       // tightEndText = util_strmin( endText, beginText + contentCheck->depth);
01276       endText = util_strmin (endText, beginText + contentCheck->depth);
01277     }
01278 
01279   char *relativeLower = 0;  // encodes the closest we should check rel to last match
01280   if (contentCheck->distance != -1)
01281     {
01282       // taking this to be relative to the END of the last match
01283       // the rule listed below maps to a regular expression of qwert.{1}uiop
01284       // alert tcp any any -> any any ("qwert"; content: "uiop"; distance: 1;)
01285       relativeLower = current + contentCheck->distance;
01286     }
01287 
01288   char *relativeHigher = &current[10000000];    // encode the farthest we should check rel to last match
01289   if (contentCheck->within != -1)
01290     {
01291       // taking this to be relative to the END of the last match
01292       relativeHigher = current + contentCheck->within;
01293     }
01294 
01295   // tighten as much as possible
01296   // char *startSearch = ( relativeLower > beginText ) ? relativeLower : beginText;
01297   char *startSearch = util_strmax (relativeLower, beginText);
01298   // char *endSearch = ( relativeHigher < endText ) ? relativeHigher : endText; 
01299   char *endSearch = util_strmin (relativeHigher, endText);
01300 
01301   // want to search for the target pattern in this range
01302   char *text;
01303   util_byte_array_t *pattern = contentCheck->content;
01304 
01305   /** \todo a test like ... content:"HTTP/1.1 403"; depth:12; 
01306      fails even when the packet starts with 
01307      HTTP/1.1 403
01308 
01309      this is because the for loop
01310      for ( i = startSearch; i < endSearch - pattern->length ; i++ ) {
01311      never starts, since startSearch == endSearch - pattern->length
01312      (because endSearch = startSearch + depth
01313 
01314      for ( i = startSearch; i < endSearch - pattern->length ; i++ ) {
01315 
01316      one fix is to check the entire range, inclusive, as below
01317    */
01318 
01319   int nocase = contentCheck->nocase;
01320   for (text = startSearch; text <= endSearch - pattern->length; text++)
01321     {
01322 
01323       // rememember memcmp returns 0 on match!
01324       // int match = !memcmp( i, pattern->bytes, pattern->length );
01325       bool match = true;
01326       int i;
01327       if (nocase == false)
01328     {
01329       for (i = 0; i < pattern->length; i++)
01330         {
01331           if (text[i] != pattern->bytes[i])
01332         {
01333           match = false;
01334           break;
01335         }
01336         }
01337     }
01338       else
01339     {
01340       for (i = 0; i < pattern->length; i++)
01341         {
01342           unsigned char t = my_isupper (text[i]) ?
01343         my_uppertolower (text[i]) : text[i];
01344           unsigned char p = my_isupper (pattern->bytes[i]) ?
01345         my_uppertolower (pattern->bytes[i]) : pattern->bytes[i];
01346           if (t != p)
01347         {
01348           match = false;
01349           break;
01350         }
01351         }
01352     }
01353 
01354       if (match)
01355     {
01356       /// \todo look at old logic again, seems incorrect:
01357       /// && !( contentCheck->negated ) ) ||
01358       ///    ( ( contentCheck->negated ) && !match ) ) {
01359       /// not sure if we're supposed to update the match pointers 
01360       /// on a negative match
01361       *lastMatchPtr = text;
01362       *currentPtr = text + pattern->length;
01363       return myxor (true, (contentCheck->negated));
01364     }
01365     }
01366   return myxor (false, (contentCheck->negated));
01367 }
01368 
01369 
01370 /**
01371   * \brief  Given an ethernet packet and a layer 7 rule, determine 
01372   * if the rule holds of the packet.
01373   * 
01374   * Pass in an array of Rlp_L7Check_t for the content check;
01375   * if it's NIL there are no content checks.
01376   */
01377 
01378 bool
01379 Evl_EthEvalL7Rule (Pkt_ProcessPkt_t * pp,
01380            Rlp_Formula_t * aL7Formula, array_t * aL7CheckArray)
01381 {
01382   Pkt_EthernetHdr_t *anEth = pp->pkt;
01383   Rlp_Formula_t *walkFormula = aL7Formula;
01384   Rlp_Formula_t *componentFormula;
01385 
01386   while (walkFormula != NIL (Rlp_Formula_t))
01387     {
01388       componentFormula = car (walkFormula);
01389       switch (componentFormula->type)
01390     {
01391     case Rlp_Ack_c:
01392       {
01393         Rlp_AckAttribute_t *ackAttribute =
01394           (Rlp_AckAttribute_t *) cdr (componentFormula);
01395         if (!EthEvalAck (anEth, ackAttribute))
01396           {         // implemented
01397         return false;
01398           }
01399         walkFormula = cdr (walkFormula);
01400         break;
01401       }
01402     case Rlp_Sameip_c:
01403       {
01404         if (!EthEvalSameIp (anEth))
01405           {         // implemented
01406         return false;
01407           }
01408         walkFormula = cdr (walkFormula);
01409         break;
01410       }
01411     case Rlp_Seq_c:
01412       {
01413         Rlp_SeqAttribute_t *seqAttribute =
01414           (Rlp_SeqAttribute_t *) cdr (componentFormula);
01415         if (!EthEvalSeq (anEth, seqAttribute))
01416           {         // implemented
01417         return false;
01418           }
01419         walkFormula = cdr (walkFormula);
01420         break;
01421       }
01422     case Rlp_Flags_c:
01423       {
01424         Rlp_FlagsAttribute_t *flagsAttribute =
01425           (Rlp_FlagsAttribute_t *) cdr (componentFormula);
01426         if (!EthEvalFlags (anEth, flagsAttribute))
01427           {
01428         return false;
01429           }
01430         walkFormula = cdr (walkFormula);
01431         break;
01432       }
01433     case Rlp_Fragbits_c:
01434       {
01435         Rlp_FragbitsAttribute_t *fragAttribute =
01436           (Rlp_FragbitsAttribute_t *) cdr (componentFormula);
01437         if (!EthEvalFrag (anEth, fragAttribute))
01438           {
01439         return false;
01440           }
01441         walkFormula = cdr (walkFormula);
01442         break;
01443       }
01444     case Rlp_Icmp_Id_c:
01445       {
01446         Rlp_IcmpIdAttribute_t *icmpIdAttribute =
01447           (Rlp_IcmpIdAttribute_t *) cdr (componentFormula);
01448         if (!EthEvalIcmpId (anEth, icmpIdAttribute))
01449           {
01450         return false;
01451           }
01452         walkFormula = cdr (walkFormula);
01453         break;
01454       }
01455     case Rlp_Icmp_Seq_c:
01456       {
01457         Rlp_IcmpSeqAttribute_t *icmpSeqAttribute =
01458           (Rlp_IcmpSeqAttribute_t *) cdr (componentFormula);
01459         if (!EthEvalIcmpSeqId (anEth, icmpSeqAttribute))
01460           {
01461         return false;
01462           }
01463         walkFormula = cdr (walkFormula);
01464         break;
01465       }
01466     case Rlp_Icode_c:
01467       {
01468         Rlp_IcodeAttribute_t *icodeAttribute =
01469           (Rlp_IcodeAttribute_t *) cdr (componentFormula);
01470         if (!EthEvalIcode (anEth, icodeAttribute))
01471           {
01472         return false;
01473           }
01474         walkFormula = cdr (walkFormula);
01475         break;
01476       }
01477     case Rlp_Id_c:
01478       {
01479         Rlp_IdAttribute_t *idAttribute =
01480           (Rlp_IdAttribute_t *) cdr (componentFormula);
01481         if (!EthEvalId (anEth, idAttribute))
01482           {
01483         return false;
01484           }
01485         walkFormula = cdr (walkFormula);
01486         break;
01487       }
01488     case Rlp_IpOpts_c:
01489       {
01490         Rlp_IpOptsAttribute_t *ipOptsAttribute =
01491           (Rlp_IpOptsAttribute_t *) cdr (componentFormula);
01492         if (!EthEvalIpOpts (anEth, ipOptsAttribute))
01493           {
01494         return false;
01495           }
01496         walkFormula = cdr (walkFormula);
01497         break;
01498       }
01499     case Rlp_Ip_Proto_c:
01500       {
01501         Rlp_IpProtoAttribute_t *ipProtoAttribute =
01502           (Rlp_IpProtoAttribute_t *) cdr (componentFormula);
01503         if (!EthEvalIpProto (anEth, ipProtoAttribute))
01504           {
01505         return false;
01506           }
01507         walkFormula = cdr (walkFormula);
01508         break;
01509       }
01510     case Rlp_Itype_c:
01511       {
01512         Rlp_ItypeAttribute_t *itypeAttribute =
01513           (Rlp_ItypeAttribute_t *) cdr (componentFormula);
01514         if (!EthEvalItype (anEth, itypeAttribute))
01515           {
01516         return false;
01517           }
01518         walkFormula = cdr (walkFormula);
01519         break;
01520       }
01521 
01522     case Rlp_Dsize_c:
01523       {
01524         Rlp_DsizeAttribute_t *dsizeAttribute =
01525           (Rlp_DsizeAttribute_t *) cdr (componentFormula);
01526         if (!EthEvalDsize (anEth, dsizeAttribute))
01527           {
01528         return false;
01529           }
01530         walkFormula = cdr (walkFormula);
01531         break;
01532       }
01533     case Rlp_Ttl_c:
01534       {
01535         Rlp_TtlAttribute_t *ttlAttribute =
01536           (Rlp_TtlAttribute_t *) cdr (componentFormula);
01537         if (!EthEvalTtl (anEth, ttlAttribute))
01538           {
01539         return false;
01540           }
01541         walkFormula = cdr (walkFormula);
01542         break;
01543       }
01544     case Rlp_Sample_c:
01545       {
01546         Rlp_SampleAttribute_t *sampleAttribute =
01547           (Rlp_SampleAttribute_t *) cdr (componentFormula);
01548         if (!EthEvalSample (pp, sampleAttribute))
01549           {
01550         return false;
01551           }
01552         walkFormula = cdr (walkFormula);
01553         break;
01554       }
01555     case Rlp_Interface_c:
01556       {
01557         Rlp_IfAttribute_t *ifAttribute =
01558           (Rlp_IfAttribute_t *) cdr (componentFormula);
01559         if (!EthEvalIf (pp, ifAttribute))
01560           {
01561         return false;
01562           }
01563         walkFormula = cdr (walkFormula);
01564         break;
01565       }
01566     case Rlp_Rpc_c:
01567       {
01568         Rlp_RpcAttribute_t *rpcAttribute =
01569           (Rlp_RpcAttribute_t *) cdr (componentFormula);
01570         if (!EthEvalRpc (anEth, rpcAttribute))
01571           {
01572         return false;
01573           }
01574         walkFormula = cdr (walkFormula);
01575         break;
01576       }
01577     case Rlp_Nocase_c:
01578     case Rlp_Within_c:
01579     case Rlp_Distance_c:
01580     case Rlp_Content_c:
01581     case Rlp_Uricontent_c:
01582     case Rlp_Depth_c:
01583     case Rlp_Offset_c:
01584     case Rlp_Byte_Jump_c:
01585     case Rlp_Byte_Test_c:
01586     case Rlp_Pcre_c:
01587       // the content checker is repsonsible for looking at these
01588       // and advancing through the list appropriately
01589       walkFormula = cdr (walkFormula);
01590       break;
01591     default:
01592       printf ("Illegal formula type, bailing\n");
01593       assert (0);
01594     }
01595     }
01596 
01597   if ((aL7CheckArray != NIL (array_t)) && (array_n (aL7CheckArray) != 0))
01598     {
01599       return Evl_EthEvalL7RuleContentCheck (anEth, aL7CheckArray);
01600     }
01601   else
01602     {
01603       return true;      // there are no content checks, and all other checks 
01604       // must have been true for us to get here
01605     }
01606 }
01607 
01608 
01609 /** \brief Pcre check */
01610 
01611 static int
01612 evalPcreCheck (char *beginText, char *endText, Rlp_PcreCheck_t * pcreCheck)
01613 {
01614   int length = endText - beginText;
01615   int ovector[30];
01616   int rc = pcre_exec (pcreCheck->re,    // result of pcre_compile() 
01617               NULL, // we didn’t study the pattern 
01618               beginText,    // the subject string 
01619               length,   // the length of the subject string 
01620               0,    // start at offset 0 in the subject
01621               0,    // default options 
01622               ovector,  // vector for substring information 
01623               30);  // number of elements in the vector
01624 
01625   if (PCRE_ERROR_NOMATCH == rc)
01626     {
01627       return false;
01628     }
01629   else
01630     {
01631       return true;
01632     }
01633 }
01634 
01635 
01636 /** \brief Allocate or reset the arrays used for storing rules */
01637 
01638 static void
01639 updateL4RuleArrays (Evl_L4Manager_t * l4mgr)
01640 {
01641   if (l4mgr->potentialRulesFromFsm == NIL (array_t))
01642     {
01643       // cannot just use the number of rules from 
01644       // the manager passed in, since that's
01645       // for the tcp/udp/other subset of rules
01646       Evl_Manager_t *globalMgr = l4mgr->mgr;
01647       int maxNumOfPossibleRules = globalMgr->numAllRules;
01648       // allocate all in one shot
01649       l4mgr->potentialRulesFromFsm = array_alloc (int, maxNumOfPossibleRules);
01650       l4mgr->rulesFromFsm = array_alloc (int, maxNumOfPossibleRules);
01651       l4mgr->rulesFromShortStringTable =
01652     array_alloc (int, maxNumOfPossibleRules);
01653       l4mgr->rulesFromNoContentTable =
01654     array_alloc (int, maxNumOfPossibleRules);
01655     }
01656   else
01657     {               // have already entered this function
01658       array_reset (l4mgr->potentialRulesFromFsm);
01659       array_reset (l4mgr->rulesFromFsm);
01660       array_reset (l4mgr->rulesFromShortStringTable);
01661       array_reset (l4mgr->rulesFromNoContentTable);
01662     }
01663 }
01664 
01665 
01666 /** \brief Update the L3 rules arrays */
01667 
01668 static void
01669 updateL3RuleArrays (Evl_Manager_t * mgr)
01670 {
01671   if (mgr->layer3Result == NIL (array_t))
01672     {
01673       // cannot just use the number of rules from 
01674       // the manager passed in, since that's
01675       // for the tcp/udp/other subset of rules
01676       int maxNumOfPossibleRules = mgr->numAllRules;
01677       // allocate all in one shot
01678       mgr->preprocessorResult = array_alloc (int, maxNumOfPossibleRules);
01679       mgr->genericResult = array_alloc (int, maxNumOfPossibleRules);
01680       mgr->layer3Result = array_alloc (int, maxNumOfPossibleRules);
01681       mgr->layer4Result = array_alloc (int, maxNumOfPossibleRules);
01682     }
01683   else
01684     {               // have already entered this function
01685       array_reset (mgr->preprocessorResult);
01686       array_reset (mgr->genericResult);
01687       array_reset (mgr->layer3Result);
01688       array_reset (mgr->layer4Result);
01689     }
01690 }
01691 
01692 
01693 /** \brief Perform preprocessing actions. */
01694 
01695 int
01696 Evl_Preprocess (Evl_L4Manager_t * preprocessorMgr, Pkt_ProcessPkt_t * pp)
01697 {
01698   int i;
01699   Evl_L4ComputeRuleSetForEth (pp, preprocessorMgr,
01700                   preprocessorMgr->mgr->preprocessorResult);
01701   for (i = 0; i < array_n (preprocessorMgr->mgr->preprocessorResult); i++)
01702     {
01703       int ruleId =
01704     array_fetch (int, preprocessorMgr->mgr->preprocessorResult, i);
01705       int globalIndex =
01706     array_fetch (int, preprocessorMgr->tcpIdToGlobalId, ruleId);
01707       Evl_Action_t *action =
01708     array_fetch (Evl_Action_t *, preprocessorMgr->mgr->actionArray,
01709              globalIndex);
01710       Evl_DoAction (action, preprocessorMgr->mgr, NIL (Evl_Bridge_t), pp);
01711     }
01712   return 0;
01713 }