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

spp_conversation.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 /* $Id$
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include <sys/types.h>
00028 #ifndef WIN32
00029 #include <sys/socket.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #endif /* WIN32 */
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #ifdef HAVE_STRINGS_H
00036 #include <strings.h>
00037 #endif
00038 
00039 #include "spp_conversation.h"
00040 #include "spp_portscan2.h"
00041 
00042 #include "generators.h"
00043 #include "decode.h"
00044 #include "plugbase.h"
00045 #include "debug.h"
00046 #include "util.h"
00047 #include "parser.h"
00048 #include "mstring.h"
00049 #include "log.h"
00050 #include "detect.h"
00051 #include "event_queue.h"
00052 
00053 #define CONV_TIMEOUT 120
00054 #define CONV_DEFAULT_MAX 65335
00055 
00056 #define OPT_TIMEOUT "timeout"
00057 #define OPT_MAX_CONV "max_conversations"
00058 #define OPT_ALLOWED_PROTOS "allowed_ip_protocols"
00059 #define OPT_ALERT_BAD_PROTO "alert_odd_protocols"
00060 
00061 /* if the conversation is going to be stored this way....
00062  *
00063  * Only thing this will really have troubles with is traffic between
00064  * the same ip
00065 */
00066 
00067 #define PACKET_FORWARD(a) (*((unsigned int*)&a->iph->ip_dst) > *((unsigned int*)&a->iph->ip_src))
00068 
00069 #define TRUE 1
00070 #define FALSE 0
00071 
00072 /* This INLINE is conflicting with the INLINE defined in bitop.h.
00073  * So, let's just add a little sanity check here.
00074  */
00075 #ifdef DEBUG
00076     #ifdef INLINE
00077         #undef INLINE
00078     #endif
00079     #define INLINE
00080 #else /* DEBUG */
00081     #ifndef INLINE
00082         #define INLINE inline
00083     #endif
00084 #endif
00085 
00086 /*********************** exported Global vars *********************/
00087 ConversationData  conv_data;
00088 
00089 
00090 /***********************Function Declaration*************/
00091 static void ConvInit(u_char* args);
00092 static void ParseConvArgs(u_char* args);
00093 static void ConvFunc(Packet* p, void *);
00094 static int ConvCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr);
00095 static int PruneConvCache(u_int32_t now, int tokill, StateRecord *keeper);
00096 static StateRecord* ConvGetSession(Packet* p);
00097 static INLINE void FillStateRecord(StateRecord *s, Packet *p);
00098 static INLINE void FillConvStats(StateRecord *s, Packet *p);
00099 /****************************************
00100  *  Register the preprocessor
00101  ****************************************/
00102 void SetupConv(void)
00103 {
00104     RegisterPreprocessor("conversation", ConvInit);
00105     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION, 
00106                             "Preprocessor: Registering Session\n"););
00107 }
00108 
00109 static void ParseConvArgs(u_char* args)
00110 {
00111     char **toks;
00112     char **stoks;
00113     char  *index;
00114     int num_toks, s_toks;
00115     int num;
00116 
00117     conv_data.timeout = CONV_TIMEOUT;
00118     conv_data.max_convs = CONV_DEFAULT_MAX;
00119     
00120     if(args == NULL || *args == '\0')
00121     {
00122         return;
00123     }
00124 
00125     /* tokenize the argument list */
00126     toks = mSplit(args, ",", 31, &num_toks, '\\');
00127 
00128     /* convert the tokens and place them into the port list
00129        strlen used to easily identify what token - yes a kludge
00130     */
00131     for(num = 0; num < num_toks; num++)
00132     {
00133         index = toks[num];
00134 
00135         while(index && isspace((int)*(index)))
00136         {
00137             index++;
00138         }
00139         
00140         if(!strncasecmp(OPT_TIMEOUT, index, strlen(OPT_TIMEOUT)))
00141         {
00142             stoks = mSplit(index, " ", 4, &s_toks, 0);
00143             if(s_toks < 2)
00144             {
00145                 FatalError("ERROR %s(%d) => No timeout argument to "
00146                            "conversation\n", file_name, file_line);
00147             }
00148 
00149             conv_data.timeout = atoi(stoks[1]);
00150             mSplitFree(&stoks, s_toks);
00151         }
00152         else if(!strncasecmp(OPT_MAX_CONV, index,
00153                              strlen(OPT_MAX_CONV)))
00154         {
00155             stoks = mSplit(index, " ", 4, &s_toks, 0);
00156             if(s_toks < 2)
00157             {
00158                 FatalError("ERROR %s(%d) => No max_conversations argument "
00159                            "to conversation\n", file_name, file_line);
00160             }
00161 
00162             conv_data.max_convs = atoi(stoks[1]);
00163             mSplitFree(&stoks, s_toks);
00164         }
00165         else if(!strncasecmp(OPT_ALLOWED_PROTOS, index,
00166                              strlen(OPT_ALLOWED_PROTOS)))
00167         {
00168             /* need to sit here and parse through what I will allow
00169                and what I won't
00170 
00171                defaults to all
00172 
00173                you can specify a list of protocols to support
00174             */
00175             char **ports;
00176             int num_ports;
00177             char *port;
00178             int j = 0;
00179             u_int32_t portnum;
00180 
00181             for(j = 0;j<256;j++)
00182             {
00183                 conv_data.allowed_ip_protocols[j] = 0;
00184             }
00185 
00186             ports = mSplit(index, " ", 40, &num_ports, 0);
00187 
00188             if(num_ports < 2)
00189             {
00190                 FatalError("ERROR %s(%d) => No ip_proto list "
00191                            "to conversation\n", file_name, file_line);
00192             }
00193 
00194             j = 1;
00195 
00196             while(j < num_ports)
00197             {
00198                 port = ports[j];
00199 
00200                 if(isdigit((int)port[0]))
00201                 {
00202                     portnum = atoi(port);
00203 
00204                     if(portnum > 255)
00205                     {
00206                         FatalError("ERROR %s(%d) => Bad ip_proto list to "
00207                                    "conversation\n", file_name, file_line);
00208                     }
00209 
00210                     conv_data.allowed_ip_protocols[portnum] = 1;
00211                 }
00212                 else if(!strncasecmp(port, "all", 3))
00213                 {
00214                     memset(&conv_data.allowed_ip_protocols, 1, 256);
00215                 }                
00216                 else
00217                 {
00218                     FatalError("ERROR %s(%d) => Bad ip_proto list to "
00219                                "conversation\n", file_name, file_line);
00220                 }
00221 
00222                 j++;
00223             }
00224             mSplitFree(&ports, num_ports);
00225         }
00226         else if(!strncasecmp(OPT_ALERT_BAD_PROTO, index,
00227                              strlen(OPT_ALERT_BAD_PROTO)))
00228         {
00229             conv_data.alert_odd_protocols = 1;
00230         }        
00231         else
00232         {
00233             FatalError("ERROR %s(%d) => Unknown argument to spp_conversation "
00234                        "preprocessor: \"%s\"\n", 
00235                        file_name, file_line, index);
00236         }
00237     }   
00238 
00239     mSplitFree(&toks, num_toks);
00240 }
00241 
00242 /****************************************
00243  *  Initialize everything
00244  ****************************************/
00245 void ConvInit(u_char* args)
00246 {
00247     int i;
00248     int printall = 1;
00249     char buf[STD_BUF+1];
00250     
00251     memset(&conv_data, 0, sizeof(ConversationData));
00252     conv_data.keepstats = 0;
00253     conv_data.alert_odd_protocols = 0;
00254 
00255     /* allow everything by default */
00256     memset(&conv_data.allowed_ip_protocols, 1, 256);
00257     
00258     ParseConvArgs(args);
00259 
00260     if(mempool_init(&conv_data.state_records,
00261                     conv_data.max_convs, sizeof(StateRecord)))
00262     {
00263         FatalError("ERROR: can't initialize state records\n");
00264     }
00265 
00266     conv_data.cachePtr = &conv_data.cache;
00267     
00268     ubi_trInitTree(conv_data.cachePtr,/* ptr to the tree head */
00269                    ConvCompareFunc,   /* comparison function */
00270                    0);                /* don't allow overwrites/duplicates */
00271 
00272     AddFuncToPreprocList(ConvFunc);
00273 
00274 
00275     LogMessage("Conversation Config:\n");
00276     LogMessage("   KeepStats: %d\n", conv_data.keepstats);
00277     LogMessage("   Conv Count: %d\n", conv_data.max_convs);
00278     LogMessage("   Timeout   : %d\n", conv_data.timeout);
00279     LogMessage("   Alert Odd?: %d\n", conv_data.alert_odd_protocols);
00280 
00281     memset(buf, 0, STD_BUF+1);
00282     snprintf(buf, STD_BUF, "   Allowed IP Protocols: ");
00283     
00284     for(i=0;i<256;i++) 
00285     {
00286         if(!conv_data.allowed_ip_protocols[i])
00287         {
00288             printall = 0;
00289             break;
00290         }
00291     }
00292 
00293     if(printall)
00294     {
00295         sfsnprintfappend(buf, STD_BUF, " All\n");
00296     }
00297     else
00298     {
00299         for(i=0;i<256;i++) 
00300         {
00301             if(conv_data.allowed_ip_protocols[i])
00302             {
00303                 sfsnprintfappend(buf, STD_BUF, "%d ", i);
00304             }
00305         }
00306     }
00307     LogMessage("%s\n", buf);
00308     
00309     conv_data.isInitialized = 1;
00310 }
00311 
00312 /****************************************
00313  *  Called for every packet
00314  ****************************************/
00315 void ConvFunc(Packet* p, void *context)
00316 {
00317     StateRecord* srecord;
00318 
00319     if(!(p->preprocessors & PP_CONVERSATION))
00320     {
00321         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION, 
00322                     "Ignoring preprocessor conversation\n"););
00323         return;
00324     }
00325     
00326     if (p->packet_flags & PKT_REBUILT_STREAM) 
00327     {
00328         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION, 
00329                     "Ignoring Rebuilt Stream\n"););
00330         return;
00331     }
00332     
00333     if (p->iph == NULL)
00334     {
00335         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00336                                 "ignoring non-ip traffic\n"));
00337         return;
00338     }
00339 
00340     /* is this an allowed ip protocol */
00341     if(conv_data.allowed_ip_protocols[p->iph->ip_proto] != 1)
00342     {
00343         if(conv_data.alert_odd_protocols == 1)
00344         {
00345             SnortEventqAdd(GENERATOR_SPP_CONV, CONV_BAD_IP_PROTOCOL, 
00346                     1, 0, 5, CONV_BAD_IP_PROTOCOL_STR, 0);
00347         }
00348         
00349         return;
00350     }
00351     
00352     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00353                             "_____________________________\n"
00354                             "%s:%u->",
00355                             inet_ntoa(p->iph->ip_src), p->sp);
00356                DebugMessage(DEBUG_CONVERSATION, "%s:%u\n",
00357                             inet_ntoa(p->iph->ip_dst), p->dp););
00358 
00359 
00360     /* This will watch portscan watch */
00361     srecord = ConvGetSession(p);
00362 
00363     /* Let's try to free up some sessions and then assign out some
00364      *
00365      * If that doesn't work for what ever reason, return out and mark
00366      * the conversation header as NULL indicating that we need to do
00367      * best effort analysis on this packet but we cna't establish it
00368      * as part of an already existing session
00369      *
00370      * would be better to try get, free, alloc, add distinctly to
00371      * avoid an extra lookup
00372      *
00373      */
00374     if(srecord == NULL)
00375     {
00376         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00377                                 "State table is full! -- %u\n",
00378                                 ubi_trCount(conv_data.cachePtr)););
00379 
00380         
00381         PruneConvCache(p->pkth->ts.tv_sec, 5, NULL);
00382 
00383         srecord = ConvGetSession(p);
00384         
00385         
00386         if(srecord == NULL)
00387         {
00388             DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00389                                     "Can't allocate even after a free\n"););
00390             // p->state = NULL;
00391             return;
00392         }
00393     }
00394     
00395     srecord->last_time.tv_sec = p->pkth->ts.tv_sec;
00396     srecord->last_time.tv_usec = p->pkth->ts.tv_usec;
00397     
00398     if(conv_data.keepstats)
00399     {
00400         FillConvStats(srecord, p);
00401     }
00402 
00403     
00404     /*
00405      * controls if we will watch for scans on new sessions with
00406      * spp_portscan2
00407      */
00408 
00409     if(conv_data.watch_scans && (!(srecord->conv_flags & CONV_MULIPACKETS)))
00410     {
00411         /* only call this if this is the first packet in a conversation */
00412         psWatch(p);
00413     }
00414 
00415 
00416     if(p->pkth->ts.tv_sec >= (conv_data.prune_time.tv_sec + conv_data.timeout))
00417     {
00418         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION, "Prune time quanta exceeded, pruning "
00419                                 "conversation cache\n"););
00420         PruneConvCache(p->pkth->ts.tv_sec, 0, NULL);
00421         conv_data.prune_time.tv_sec = p->pkth->ts.tv_sec;
00422     }
00423 
00424 }
00425 
00426 /* Function: StateRecord* ConvAlloc(unsigned long cur_time)
00427  * 
00428  * Purpose: get a new state record from
00429  * Args:
00430  * 
00431  * Returns:n
00432  */ 
00433 StateRecord* ConvAlloc(unsigned long cur_time)
00434 {
00435     MemBucket* bp;
00436     StateRecord *sr;
00437     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION, "Getting free state\n"););
00438 
00439     bp = mempool_alloc(&conv_data.state_records);
00440 
00441     if(bp == NULL)
00442     {
00443         
00444         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00445                                 "State Table is full! used: %u max: %u\n",
00446                                 conv_data.max_convs););
00447         return NULL;
00448     }
00449     
00450     /* the container has to know what bucket it came from */
00451     sr = bp->data;
00452     sr->bucket = bp;
00453 
00454     return sr;    
00455 }
00456 
00457 void ConvDelete(StateRecord *sr)
00458 {
00459     /*
00460      * need to have a set of call back functions that occur when a
00461      * conversation is deleted.
00462      *
00463      * Eventually, stream4 will be able to delete conversations as
00464      * well as this one so that someone using the same pair of ports
00465      * all the time will be detected.  That's why the function is
00466      * exported.
00467      */
00468 
00469     MemBucket *mb;
00470 
00471     mb = sr->bucket;
00472 
00473     ubi_sptRemove(conv_data.cachePtr, (ubi_btNodePtr) sr);
00474     mempool_free(&conv_data.state_records, mb);
00475 }
00476 
00477 /* Function: static INLINE void FillConvStats(StateRecord *s, Packet* p)
00478  * 
00479  * Purpose: populate the packet data statistics for this conversation
00480  * Args:
00481  * 
00482  * Returns:
00483  */ 
00484 static INLINE void FillConvStats(StateRecord *s, Packet *p)
00485 {
00486     if(PACKET_FORWARD(p))
00487     {
00488         s->bytes_sent += p->caplen;
00489         s->dsize_sent += p->dsize;
00490         s->pkts_sent++;
00491     }
00492     else
00493     {
00494         s->bytes_recv += p->caplen;
00495         s->dsize_recv += p->dsize;
00496         s->pkts_recv++;
00497     }
00498 }
00499 
00500 
00501 /***********************************************
00502  * Fills the state record with info
00503  ***********************************************/
00504 static INLINE void FillStateRecord(StateRecord* s, Packet* p)
00505 {
00506     /*
00507       always store things the same way so that when we have to look
00508       up a session, we only have to look them up one way.
00509     */
00510 
00511     s->ip_proto = p->iph->ip_proto;
00512 
00513     if(PACKET_FORWARD(p))
00514     {
00515         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00516                                 "going forward!\n"););
00517         s->sip = p->iph->ip_src.s_addr;
00518         s->dip = p->iph->ip_dst.s_addr;
00519         s->sport = p->sp;
00520         s->dport = p->dp;
00521     }
00522     else
00523     {
00524         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00525                                 "going switcheroo ninja style!\n"););
00526         s->sip = p->iph->ip_dst.s_addr;
00527         s->dip = p->iph->ip_src.s_addr;
00528         s->sport = p->dp;
00529         s->dport = p->sp;
00530     }
00531 
00532     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00533                             "s->sip: %X, s->dip: %X "
00534                             "s->sport: %d s->dport: %d s->ip_proto: %d\n",
00535                             s->sip, s->dip, s->sport,s->dport,s->ip_proto););
00536 
00537     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00538                             "p->iph->ip_src.s_addr: %X, p->iph->ip_dst.s_addr: %X "
00539                             "p->sp: %d p->dp: %d p->iph->ip_proto: %d\n",
00540                             (u_int32_t) p->iph->ip_src.s_addr,
00541                             (u_int32_t) p->iph->ip_dst.s_addr,
00542                             p->sp,p->dp,p->iph->ip_proto););
00543 
00544 
00545 }
00546 
00547 
00548 /***********************************************
00549  * Find a session from the hash.
00550  * returns a pointer to that session.
00551  * allocates a new session if not found
00552  ***********************************************/
00553 static StateRecord* ConvGetSession(Packet* p)
00554 {
00555     /* We should probably only do the look up once and obliterate the
00556        original session */    
00557     StateRecord tmp;
00558     MemBucket *mb = NULL;
00559     StateRecord *ret = NULL;
00560 
00561     /* FIXME -- this shouldn't be needed */
00562     bzero(&tmp, sizeof(StateRecord));
00563 
00564     /* Searches it's own junk */
00565     FillStateRecord(&tmp, p);
00566     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00567                             "tmp.sip: %X, tmp.dip: %X "
00568                             "tmp.sport: %d tmp.dport: %d tmp.ip_proto: %d\n",
00569                             tmp.sip, tmp.dip, tmp.sport,tmp.dport,tmp.ip_proto););
00570 
00571     
00572     
00573     ret = (StateRecord *) ubi_sptFind(conv_data.cachePtr,
00574                                       (ubi_btItemPtr) &tmp);
00575 
00576     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00577                             "ret from the sptFind is %p\n", ret););
00578   
00579     if(ret == NULL)
00580     {
00581         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00582                                 "Conversation not found... allocating a new one\n"););
00583 
00584         mb = mempool_alloc(&conv_data.state_records);
00585 
00586         if(mb == NULL)
00587         {
00588             /* return NULL, free up some conversations, try to assign
00589                again
00590             */
00591             DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00592                                     "mempool is out of state records\n"););
00593                                     
00594             return NULL;
00595         }
00596         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00597                                 "allocated: %p\n", mb->data););
00598 
00599         
00600         ret = (StateRecord *) mb->data;
00601         ret->bucket = mb;
00602 
00603         FillStateRecord(ret, p);
00604                 
00605         if(ubi_sptInsert(conv_data.cachePtr,
00606                          (ubi_btNodePtr) ret,
00607                          (ubi_btNodePtr) ret, NULL) == ubi_trFALSE)
00608         {
00609             DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00610                                     "insertion into splay tree failed for ret==%p\n", ret););
00611             return NULL;
00612         }
00613         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00614                                 "insertion into splay tree succeed for ret==%p\n", ret););
00615 
00616                        
00617 
00618 
00619         /*
00620          * When we assign new conversation ID, the greater IP is
00621          * always declared to be "sip".  This flag check allows us to
00622          * know who was the first talker.
00623          */
00624         
00625         if(PACKET_FORWARD(p))
00626         {
00627             ret->conv_flags |= CONV_FORWARD;
00628         }
00629         else
00630         {
00631             ret->conv_flags |= CONV_REVERSED;
00632         }
00633 
00634     }
00635     else /* ret != NULL */
00636     {
00637         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00638                                 "Conversation found @ %p\n", ret););
00639 
00640         ret->conv_flags |= CONV_MULIPACKETS;
00641     }
00642     
00643     return ret;
00644 }
00645 
00646 /* Returns -1 if A < B
00647    Returns 1 if A > B
00648    Returns 0 if A = B */
00649 static int ConvCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
00650 {
00651     StateRecord *A = (StateRecord *) ItemPtr;
00652     StateRecord *B = (StateRecord *) NodePtr;
00653 #ifdef DEBUG
00654 
00655     #define IPLEN 256
00656     char sip[IPLEN];
00657 
00658     strncpy(sip, inet_ntoa(*(struct in_addr *) &A->sip), IPLEN);
00659     DebugMessage(DEBUG_PORTSCAN2,"A %d %s:%d -> %s:%d\n",
00660                  A->ip_proto,
00661                  sip,
00662                  A->sport,
00663                  inet_ntoa(*(struct in_addr *) &A->dip),
00664                  A->dport);
00665 
00666     strncpy(sip, inet_ntoa(*(struct in_addr *) &B->sip), IPLEN);
00667     DebugMessage(DEBUG_PORTSCAN2,"B %d %s:%d -> %s:%d\n",
00668                  B->ip_proto,
00669                  sip,
00670                  B->sport,
00671                  inet_ntoa(*(struct in_addr *) &B->dip),
00672                  B->dport);
00673 
00674     #undef IPLEN
00675 #endif /* DEBUG */
00676 
00677     
00678 
00679     if(A->sip > B->sip)
00680     {
00681         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning 1\n"););
00682         return 1;
00683     }
00684 
00685     if(A->sip < B->sip)
00686     {
00687         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning -1\n"););
00688         return -1;
00689     }
00690 
00691     
00692     if(A->dip > B->dip)
00693     {
00694         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning 1\n"););
00695         return 1;
00696     }
00697     
00698     if(A->dip < B->dip)
00699     {
00700         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning -1\n"););
00701         return -1;
00702     }
00703     
00704     /* ok the IPs are equal */
00705     if(A->sport > B->sport)
00706     {
00707         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning 1\n"););
00708         return 1;
00709     }
00710 
00711     
00712     if(A->sport < B->sport)
00713     {
00714         DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,"returning -1, count: %u\n",
00715                                 ubi_trCount(conv_data.cachePtr)
00716                                 ););
00717         return -1;
00718     }
00719     
00720     if(A->dport > B->dport) return 1;
00721     if(A->dport < B->dport) return -1;
00722 
00723     /* now lets check the protocol, maybe this should be first but I
00724        think that most networks only see tcp traffic with a little
00725        DNS -- cmg
00726     */
00727 
00728     if(A->ip_proto > B->ip_proto) return 1;
00729     if(A->ip_proto < B->ip_proto) return -1;
00730 
00731 #ifdef DEBUG
00732     DebugMessage(DEBUG_CONVERSATION, "returning 0 for session equalness\n");
00733 
00734     DebugMessage(DEBUG_CONVERSATION,
00735                  "A->sip: %u B->sip: %u A->sport: %d"
00736                  "B->dport: %d A->ip_proto %d B->ip_proto: %d\n",
00737                  A->sip, B->sip, A->sport, B->sport, A->ip_proto, B->ip_proto
00738                  );
00739 #endif /* DEBUG */
00740 
00741     return 0;
00742 }
00743 
00744 static int PruneConvCache(u_int32_t now, int tokill, StateRecord *keeper)
00745 {
00746     StateRecord *idx;
00747     u_int32_t pruned = 0;
00748 
00749     if(ubi_trCount(conv_data.cachePtr) <= 1)
00750     {
00751         return 0;
00752     }
00753 
00754     /* Number of things that need to be deleted */
00755     if(tokill == 0)
00756     {
00757         idx = (StateRecord *) ubi_btFirst((ubi_btNodePtr)conv_data.cachePtr->root);
00758 
00759         if(idx == NULL)
00760         {
00761             return 0;
00762         }
00763 
00764         do
00765         {
00766             if(idx == keeper)
00767             {
00768                 idx = (StateRecord *) ubi_btNext((ubi_btNodePtr)idx);
00769                 continue;
00770             }
00771 
00772             if((idx->last_time.tv_sec+conv_data.timeout) < now)
00773             {
00774                 StateRecord *savidx = idx;
00775 
00776                 if(ubi_trCount(conv_data.cachePtr) > 1)
00777                 {
00778                     idx = (StateRecord *) ubi_btNext((ubi_btNodePtr)idx);
00779                     DEBUG_WRAP(DebugMessage(DEBUG_CONVERSATION,
00780                                             "pruning stale conversation\n"););
00781                     ConvDelete(savidx);
00782                     pruned++;
00783                 }
00784                 else
00785                 {
00786                     ConvDelete(savidx);
00787                     pruned++;
00788                     return pruned;
00789                 }
00790             }
00791             else
00792             {
00793                 if(idx != NULL && ubi_trCount(conv_data.cachePtr))
00794                 {
00795                     idx = (StateRecord *) ubi_btNext((ubi_btNodePtr)idx);
00796                 }
00797                 else
00798                 {
00799                     return pruned;
00800                 }
00801             }
00802         } while(idx != NULL);
00803 
00804         return pruned;
00805     }
00806     else
00807     {
00808         while(tokill-- &&  ubi_trCount(conv_data.cachePtr) > 1)
00809         {
00810             idx = (StateRecord *) ubi_btLeafNode((ubi_btNodePtr)conv_data.cachePtr);
00811             if(idx != keeper)
00812                 ConvDelete(idx);
00813         }
00814 #ifdef DEBUG
00815         if(tokill > 0)
00816         {
00817             DebugMessage(DEBUG_STREAM, "Emptied out the conversation cache"
00818                          "completely tokill: %d\n",
00819                          tokill);
00820         }
00821 #endif /* DEBUG */
00822 
00823         return 0;
00824     }
00825 
00826     return 0;
00827 }
00828 

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