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

snort_stream4_session.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004 ** Copyright (C) 2005 Sourcefire, Inc.
00005 ** AUTHOR: Steven Sturges <ssturges@sourcefire.com>
00006 **
00007 ** This program is free software; you can redistribute it and/or modify
00008 ** it under the terms of the GNU General Public License as published by
00009 ** the Free Software Foundation; either version 2 of the License, or
00010 ** (at your option) any later version.
00011 **
00012 ** This program is distributed in the hope that it will be useful,
00013 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 ** GNU General Public License for more details.
00016 **
00017 ** You should have received a copy of the GNU General Public License
00018 ** along with this program; if not, write to the Free Software
00019 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 */
00021 
00022 /* snort_stream4_session.c
00023  * 
00024  * Purpose: Hash Table implementation of session management functions for
00025  *          TCP stream preprocessor.
00026  *
00027  * Arguments:
00028  *   
00029  * Effect:
00030  *
00031  * Comments:
00032  *
00033  * Any comments?
00034  *
00035  */
00036 
00037 #include "sfxhash.h"
00038 #include "ubi_SplayTree.h"
00039 #include "decode.h"
00040 #include "debug.h"
00041 #include "stream.h"
00042 #include "log.h"
00043 
00044 /* splay tree root data */
00045 static ubi_trRoot s_cache;
00046 static ubi_trRootPtr RootPtr = &s_cache;
00047 
00048 /* Stuff defined in stream4.c that we use */
00049 extern void DeleteSession(Session *, u_int32_t);
00050 extern Stream4Data s4data;
00051 extern u_int32_t stream4_memory_usage;
00052 #ifdef GIDS
00053 //extern void TraverseFuncTruncate(ubi_trNodePtr NodePtr, void *build_data);
00054 extern void SegmentTruncTraverse(Stream *, u_int16_t);
00055 #endif /* GIDS */
00056 
00057 #ifdef USE_HASH_TABLE
00058 static SFXHASH *sessionHashTable = NULL;
00059 #endif
00060 
00061 #ifndef WIN32
00062 #include <sys/socket.h>
00063 #include <netinet/in.h>
00064 #include <arpa/inet.h>
00065 #endif
00066 
00067 #ifdef USE_HASH_TABLE
00068 int GetSessionCount()
00069 {
00070     if (sessionHashTable)
00071         return sessionHashTable->count;
00072     else
00073         return 0;
00074 }
00075 
00076 int GetSessionKey(Packet *p, SessionHashKey *key)
00077 {
00078     if (!key)
00079         return 0;
00080 
00081 //    printf("%s: %u %d %u %d\n", __FUNCTION__, p->iph->ip_src.s_addr, p->tcph->th_sport, p->iph->ip_dst.s_addr, p->tcph->th_dport);
00082 
00083     if (p->iph->ip_src.s_addr < p->iph->ip_dst.s_addr)
00084     {
00085         key->lowIP = p->iph->ip_src.s_addr;
00086         key->port = p->tcph->th_sport;
00087         key->highIP = p->iph->ip_dst.s_addr;
00088         key->port2 = p->tcph->th_dport;
00089     }
00090     else if (p->iph->ip_src.s_addr == p->iph->ip_dst.s_addr)
00091     {
00092         key->lowIP = p->iph->ip_src.s_addr;
00093         key->highIP = p->iph->ip_dst.s_addr;
00094         if (p->tcph->th_sport < p->tcph->th_dport)
00095         {
00096             key->port = p->tcph->th_sport;
00097             key->port2 = p->tcph->th_dport;
00098         }
00099         else
00100         {
00101             key->port = p->tcph->th_sport;
00102             key->port2 = p->tcph->th_dport;
00103         }
00104     }
00105     else
00106     {
00107         key->lowIP = p->iph->ip_dst.s_addr;
00108         key->port = p->tcph->th_dport;
00109         key->highIP = p->iph->ip_src.s_addr;
00110         key->port2 = p->tcph->th_sport;
00111     }
00112 
00113 #if defined(_LP64)
00114     key->pad1 = key->pad2 = 0;
00115 #endif
00116 
00117 //    printf("%s: %u %d %u %d\n", __FUNCTION__, key->lowIP, key->port, key->highIP, key->port2);
00118     return 1;
00119 }
00120 
00121 Session *GetSessionFromHashTable(Packet *p)
00122 {
00123     Session *returned = NULL;
00124     SFXHASH_NODE *hnode;
00125     SessionHashKey sessionKey;
00126 
00127 //printf("%s:start\n", __FUNCTION__);
00128 //printf("%s: %u %d %u %d\n", __FUNCTION__, p->iph->ip_src.s_addr, p->tcph->th_sport, p->iph->ip_dst.s_addr, p->tcph->th_dport);
00129 
00130     if (!GetSessionKey(p, &sessionKey))
00131         return NULL;
00132 
00133 //printf("%s:we have a key\n", __FUNCTION__);
00134 
00135     hnode = sfxhash_find_node(sessionHashTable, &sessionKey);
00136 
00137     if (hnode && hnode->data)
00138     {
00139         /* This is a unique hnode, since the sfxhash finds the
00140          * same key before returning this node.
00141          */
00142         returned = (Session *)hnode->data;
00143     }
00144 //printf("%s:returned %p\n", __FUNCTION__, returned);
00145     return returned;
00146 }
00147 
00148 int RemoveSessionFromHashTable(Session *ssn)
00149 {
00150     return sfxhash_remove(sessionHashTable, &(ssn->hashKey));
00151 }
00152 
00153 int CleanHashTable(u_int32_t thetime, Session *save_me, int memCheck)
00154 {
00155     Session *idx;
00156     u_int32_t pruned = 0;
00157 
00158     if (thetime != 0)
00159     {
00160         char got_one;
00161         idx = (Session *) sfxhash_lru(sessionHashTable);
00162 
00163         if(idx == NULL)
00164         {
00165             return 0;
00166         }
00167 
00168         do
00169         {
00170             got_one = 0;            
00171             if(idx == save_me)
00172             {
00173                 SFXHASH_NODE *lastNode = sfxhash_lru_node(sessionHashTable);
00174                 sfxhash_gmovetofront(sessionHashTable, lastNode);
00175                 lastNode = sfxhash_lru_node(sessionHashTable);
00176                 if ((lastNode) && (lastNode->data != idx))
00177                 {
00178                     idx = (Session *)lastNode->data;
00179                     continue;
00180                 }
00181                 else
00182                 {
00183                     return pruned;
00184                 }
00185             }
00186 
00187             if((idx->last_session_time+s4data.timeout) < thetime)
00188             {
00189                 Session *savidx = idx;
00190 
00191                 if(sfxhash_count(sessionHashTable) > 1)
00192                 {
00193                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning stale session\n"););
00194                     DeleteSession(savidx, thetime);
00195                     idx = (Session *) sfxhash_lru(sessionHashTable);
00196                     pruned++;
00197                     got_one = 1;
00198                 }
00199                 else
00200                 {
00201                     DeleteSession(savidx, thetime);
00202                     pruned++;
00203                     return pruned;
00204                 }
00205             }
00206             else
00207             {
00208                 return pruned;
00209             }
00210         } while ((idx != NULL) && (got_one == 1));
00211 
00212         return pruned;
00213     }
00214     else if (s4data.cache_clean_percent == 0)
00215     {
00216         /* Free up xxx sessions at a time until we get under the
00217          * memcap or free enough sessions to be able to create
00218          * new ones.
00219          */
00220         while ( ((memCheck && (stream4_memory_usage > s4data.memcap)) ||
00221                  (sessionHashTable->count >
00222                    (s4data.max_sessions - s4data.cache_clean_sessions))) &&
00223                 (sfxhash_count(sessionHashTable) > 1))
00224         {
00225             int i;
00226             idx = (Session *) sfxhash_lru(sessionHashTable);
00227             for (i=0;i<s4data.cache_clean_sessions && 
00228                      (sfxhash_count(sessionHashTable) > 1); i++)
00229             {
00230                 if(idx != save_me)
00231                 {
00232                     DeleteSession(idx, thetime);
00233                     pruned++;
00234                     idx = (Session *) sfxhash_lru(sessionHashTable);
00235                 }
00236                 else
00237                 {
00238                     SFXHASH_NODE *lastNode = sfxhash_lru_node(sessionHashTable);
00239                     sfxhash_gmovetofront(sessionHashTable, lastNode);
00240                     lastNode = sfxhash_lru_node(sessionHashTable);
00241                     if ((lastNode) && (lastNode->data == idx))
00242                     {
00243                         /* Okay, this session is the only one left */
00244                         break;
00245                     }
00246                     idx = (Session *) sfxhash_lru(sessionHashTable);
00247                     i--; /* Didn't clean this one */
00248                 }
00249             }
00250         }
00251     }
00252     else
00253     {
00254         /* Free up a percentage of the cache */
00255         u_int32_t smallPercent = (u_int32_t)(s4data.max_sessions *
00256                         s4data.cache_clean_percent);
00257         idx = (Session *) sfxhash_lru(sessionHashTable);
00258         while ((stream4_memory_usage > (s4data.memcap - smallPercent)) &&
00259                 (sfxhash_count(sessionHashTable) > 1))
00260         {
00261             idx = (Session *) sfxhash_lru(sessionHashTable);
00262             if(idx != save_me)
00263             {
00264                 DeleteSession(idx, thetime);
00265                 pruned++;
00266                 idx = (Session *) sfxhash_lru(sessionHashTable);
00267             }
00268             else
00269             {
00270                 SFXHASH_NODE *lastNode = sfxhash_lru_node(sessionHashTable);
00271                 sfxhash_gmovetofront(sessionHashTable, lastNode);
00272                 lastNode = sfxhash_lru_node(sessionHashTable);
00273                 if ((lastNode) && (lastNode->data == idx))
00274                 {
00275                     /* Okay, this session is the only one left */
00276                     break;
00277                 }
00278                 idx = (Session *) sfxhash_lru(sessionHashTable);
00279             }
00280         }
00281     }
00282     return pruned;
00283 }
00284 
00285 Session *GetNewSession(Packet *p)
00286 {
00287     Session *retSsn = NULL;
00288     SessionHashKey sessionKey;
00289     SFXHASH_NODE *hnode;
00290 
00291     if (!GetSessionKey(p, &sessionKey))
00292         return retSsn;
00293 
00294     hnode = sfxhash_get_node(sessionHashTable, &sessionKey);
00295     if (!hnode)
00296     {
00297         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "HashTable full, clean it\n"););
00298         if (!CleanHashTable(p->pkth->ts.tv_sec, NULL, 0))
00299         {
00300             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "HashTable full, no timeouts, clean it\n"););
00301             CleanHashTable(0, NULL, 0);
00302         }
00303 
00304         /* Should have some freed nodes now */
00305         hnode = sfxhash_get_node(sessionHashTable, &sessionKey);
00306 #ifdef DEBUG
00307         if (!hnode)
00308         {
00309             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Problem, no freed nodes\n"););
00310         }
00311 #endif
00312     }
00313     if (hnode && hnode->data)
00314     {
00315         retSsn = hnode->data;
00316 
00317         memset(retSsn, 0, sizeof(Session));
00318 
00319         /* Save the session key for future use */
00320         memcpy(&(retSsn->hashKey), &sessionKey,
00321                         sizeof(SessionHashKey));
00322 
00323 #if 0
00324         retSsn->ttl = 0;
00325         retSsn->alert_count = 0;
00326         retSsn->http_alert_flags = 0;
00327         retSsn->preproc_data = NULL;
00328         retSsn->preproc_free = NULL;
00329         retSsn->preproc_proto = 0;
00330 #endif
00331     }
00332     return retSsn;
00333 }
00334 #endif
00335 
00336 Session *GetSessionFromSplayTree(Packet *p)
00337 {
00338     Session idx;
00339     Session *returned;
00340 #ifdef DEBUG
00341     char flagbuf[9];
00342     CreateTCPFlagString(p, flagbuf);
00343 #endif
00344 
00345     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Trying to get session...\n"););
00346     idx.server.ip = p->iph->ip_src.s_addr;
00347     idx.client.ip = p->iph->ip_dst.s_addr;
00348     idx.server.port = p->sp;
00349     idx.client.port = p->dp;
00350 
00351     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Looking for sip: 0x%X sp: %d  cip: "
00352                 "0x%X cp: %d flags: %s\n", idx.server.ip, idx.server.port, 
00353                 idx.client.ip, idx.client.port, flagbuf););
00354 
00355     returned = (Session *) ubi_sptFind(RootPtr, (ubi_btItemPtr)&idx);
00356 
00357     if(returned == NULL)
00358     {
00359         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "GetSession forward didn't work, "
00360                     "trying backwards...\n"););
00361         idx.server.ip = p->iph->ip_dst.s_addr;
00362         idx.client.ip = p->iph->ip_src.s_addr;
00363         idx.server.port = p->dp;
00364         idx.client.port = p->sp;
00365         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Looking for sip: 0x%X sp: %d  "
00366                                 "cip: 0x%X cp: %d flags: %s\n", idx.server.ip, 
00367                                 idx.server.port, idx.client.ip, idx.client.port,
00368                                 flagbuf););
00369         returned = (Session *) ubi_sptFind(RootPtr, (ubi_btItemPtr)&idx);
00370     }
00371 
00372     if(returned == NULL)
00373     {
00374         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Unable to find session\n"););
00375     }
00376     else
00377     {
00378         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Found session\n"););
00379     }
00380 
00381     return returned;
00382 
00383 }
00384 
00385 Session *RemoveSession(Session *ssn)
00386 {
00387 #ifdef USE_HASH_TABLE
00388     if (!RemoveSessionFromHashTable(ssn) )
00389         return ssn;
00390     else
00391         return NULL;
00392 #else /* USE_SPLAY_TREE */
00393     Session *killme = NULL;
00394     if(ubi_trCount(RootPtr))
00395     {
00396         killme = (Session *) ubi_sptRemove(RootPtr, (ubi_btNodePtr) ssn);
00397     }
00398     return killme;
00399 #endif
00400 }
00401 
00402 Session *GetSession(Packet *p)
00403 {
00404 #ifdef USE_HASH_TABLE
00405     return GetSessionFromHashTable(p);
00406 #else /* USE_SPLAY_TREE */
00407     return GetSessionFromSplayTree(p);
00408 #endif
00409 }
00410 
00411 #ifdef USE_HASH_TABLE
00412 #else /* USE_SPLAY_TREE */
00413 static int CompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
00414 {
00415     Session *nSession;
00416     Session *iSession; 
00417 
00418     nSession = ((Session *)NodePtr);
00419     iSession = (Session *)ItemPtr;
00420 
00421     if(nSession->server.ip < iSession->server.ip) return 1;
00422     else if(nSession->server.ip > iSession->server.ip) return -1;
00423 
00424     if(nSession->client.ip < iSession->client.ip) return 1;
00425     else if(nSession->client.ip > iSession->client.ip) return -1;
00426         
00427     if(nSession->server.port < iSession->server.port) return 1;
00428     else if(nSession->server.port > iSession->server.port) return -1;
00429 
00430     if(nSession->client.port < iSession->client.port) return 1;
00431     else if(nSession->client.port > iSession->client.port) return -1;
00432 
00433     return 0;
00434 }
00435 #endif
00436 
00437 void InitSessionCache()
00438 {
00439 #ifdef USE_HASH_TABLE
00440     if (!sessionHashTable)
00441     {
00442         /* Create the hash table --
00443          * SESSION_HASH_TABLE_SIZE hash buckets
00444          * keysize = 12 bytes (2x 32bit IP, 2x16bit port)
00445          * data size = sizeof(Session) object
00446          * no max mem
00447          * no automatic node recovery
00448          * NULL node recovery free function
00449          * NULL user data free function
00450          * recycle nodes
00451          */
00452         /* Rule of thumb, size should be 1.4 times max to avoid
00453          * collisions.
00454          */
00455         int hashTableSize = (int) (s4data.max_sessions * 1.4);
00456         int maxSessionMem = s4data.max_sessions * (
00457                              sizeof(Session) +
00458                              sizeof(SFXHASH_NODE) +
00459                              sizeof(SessionHashKey) +
00460                              sizeof (SFXHASH_NODE *));
00461         int tableMem = (hashTableSize +1) * sizeof(SFXHASH_NODE*);
00462         int maxMem = maxSessionMem + tableMem;
00463         sessionHashTable = sfxhash_new(hashTableSize,
00464                         sizeof(SessionHashKey),
00465                         sizeof(Session), maxMem, 0, NULL, NULL, 1);
00466 
00467 
00468     }
00469 #else /* USE_SPLAY_TREE */
00470     (void)ubi_trInitTree(RootPtr,       /* ptr to the tree head */
00471                          CompareFunc,   /* comparison function */
00472                          0);            /* don't allow overwrites/duplicates */
00473 
00474 #endif
00475 }
00476 
00477 void PurgeSessionCache()
00478 {
00479     Session *ssn = NULL;
00480 #ifdef USE_HASH_TABLE
00481     ssn = (Session *)sfxhash_mru(sessionHashTable);
00482 #else /* USE_SPLAY_TREE */
00483     ssn = (Session *)ubi_trFirst(RootPtr);
00484 #endif
00485     while (ssn)
00486     {
00487         DeleteSession(ssn, 0);
00488 #ifdef USE_HASH_TABLE
00489         ssn = (Session *)sfxhash_mru(sessionHashTable);
00490 #else /* USE_SPLAY_TREE */
00491         ssn = (Session *)ubi_trFirst(RootPtr);
00492 #endif
00493     }
00494 }
00495 
00496 void PrintSessionCache()
00497 {
00498 #ifdef USE_HASH_TABLE
00499     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "%lu streams active, %u bytes in use\n", 
00500                             sfxhash_count(sessionHashTable), stream4_memory_usage););
00501 #else /* USE_SPLAY_TREE */
00502     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "%lu streams active, %u bytes in use\n", 
00503                             ubi_trCount(RootPtr), stream4_memory_usage););
00504 #endif
00505     return;
00506 }
00507 
00508 int PruneSessionCache(u_int32_t thetime, int mustdie, Session *save_me)
00509 {
00510 #ifdef USE_HASH_TABLE
00511     return CleanHashTable(thetime, save_me, 1);
00512 #else /* USE_SPLAY_TREE */
00513     Session *idx;
00514     u_int32_t pruned = 0;
00515 
00516     if(ubi_trCount(RootPtr) == 0)
00517     {
00518         return 0;
00519     }
00520 
00521     {
00522         if (thetime != 0)
00523         {
00524             char got_one;
00525             idx = (Session *) ubi_btLast((ubi_btNodePtr)RootPtr->root);
00526 
00527             if(idx == NULL)
00528             {
00529                 return 0;
00530             }
00531 
00532             do
00533             {
00534                 got_one = 0;            
00535                 if(idx == save_me)
00536                 {
00537                     idx = (Session *) ubi_btPrev((ubi_btNodePtr)idx);
00538                     continue;
00539                 }
00540 
00541                 if((idx->last_session_time+s4data.timeout) < thetime)
00542                 {
00543                     Session *savidx = idx;
00544 
00545                     if(ubi_trCount(RootPtr) > 1)
00546                     {
00547                         idx = (Session *) ubi_btPrev((ubi_btNodePtr)idx);
00548                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning stale session\n"););
00549                         DeleteSession(savidx, thetime);
00550                         pruned++;
00551                         got_one = 1;
00552                     }
00553                     else
00554                     {
00555                         DeleteSession(savidx, thetime);
00556                         pruned++;
00557                         return pruned;
00558                     }
00559                 }
00560                 else
00561                 {
00562                     if(idx != NULL && ubi_trCount(RootPtr))
00563                     {
00564                         idx = (Session *) ubi_btPrev((ubi_btNodePtr)idx);
00565                     }
00566                     else
00567                     {
00568                         return pruned;
00569                     }
00570                 }
00571             } while ((idx != NULL) && (got_one == 1));
00572 
00573             return pruned;
00574         }
00575         else if (s4data.cache_clean_percent == 0)
00576         {
00577             /* Free up xxx sessions at a time until we get under the
00578              * memcap */
00579             while ((stream4_memory_usage > s4data.memcap) &&
00580                    ubi_trCount(RootPtr) > 1)
00581             {
00582                 int i;
00583                 idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00584                 for (i=0;i<s4data.cache_clean_sessions && 
00585                          ubi_trCount(RootPtr) > 1; i++)
00586                 {
00587                     if(idx != save_me)
00588                     {
00589                         DeleteSession(idx, thetime);
00590                         pruned++;
00591                         idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00592                     }
00593                     else
00594                     {
00595                         Rotate((ubi_btNodePtr)idx);
00596                         idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00597                         i--; /* Didn't clean this one */
00598                     }
00599                 }
00600             }
00601         }
00602         else
00603         {
00604             /* Free up a percentage of the cache */
00605             u_int32_t smallPercent = (u_int32_t)(s4data.memcap * s4data.cache_clean_percent);
00606             idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00607             while ((stream4_memory_usage > (s4data.memcap - smallPercent)) &&
00608                    ubi_trCount(RootPtr) > 1)
00609             {
00610                 if(idx != save_me)
00611                 {
00612                     DeleteSession(idx, thetime);
00613                     pruned++;
00614                     idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00615                 }
00616                 else
00617                 {
00618                     Rotate((ubi_btNodePtr)idx);
00619                     idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00620                 }
00621             }
00622         }
00623 #ifdef DEBUG
00624         if(ubi_trCount(RootPtr) == 1) {
00625             DebugMessage(DEBUG_STREAM, "Emptied out the stream cache "
00626                          "completely mustdie: %d, memusage: %u\n",
00627                          mustdie,
00628                          stream4_memory_usage);
00629         }
00630 #endif /* DEBUG */
00631         return pruned;
00632     }
00633 #endif /* USE_HASH_TABLE */
00634 
00635     return 0;
00636 }
00637 
00638 
00639 #ifdef GIDS
00640 #ifdef USE_HASH_TABLE
00641 void TruncSession(Session *idx, u_int32_t thetime)
00642 {
00643     Stream *s;
00644     u_int16_t bytes_to_clear = 0;
00645 
00646     /* client */
00647     if(idx->client.last_trunc_time != thetime)
00648     {
00649         //DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00650         //printf("TruncHashTable: client: %d (%p).\n", idx->client.bytes_tracked, idx);
00651         //);
00652 
00653         s = &idx->client;
00654 
00655         /* only try to truncate if there is data in the stream
00656          * and there is at least one spd in the stream.
00657          */
00658         if(s->bytes_tracked > 0 && ubi_trCount(&s->data) > 1)
00659         {
00660             /* here we determine what we want to cut off */
00661             bytes_to_clear = (s->bytes_tracked / 100) * s4data.truncate_cut_off_perc;
00662 
00663             //DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00664             //printf("%5d -> %5d: stream_size: %5d: Going to try to truncate %d bytes (%d%%)\n", idx->client.port, idx->server.port, s->bytes_tracked, bytes_to_clear, s4data.truncate_cut_off_perc);
00665             //);
00666 
00667             SegmentTruncTraverse(s, bytes_to_clear);
00668 
00669             //printf("%5d -> %5d: stream_size: %5d\n", idx->client.port, idx->server.port, s->bytes_tracked);
00670         }
00671                 
00672         /* only truncate the stream once this 'time'. */
00673         idx->client.last_trunc_time = thetime;
00674     }
00675     /* server */
00676     if(idx->server.last_trunc_time != thetime)
00677     {
00678         //DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00679         //printf("TruncHashTable: server: %d (%p).\n", idx->server.bytes_tracked, idx);
00680         //);
00681 
00682         s = &idx->server;
00683 
00684         /* only try to truncate if there is data in the stream
00685          * and there is at least one spd in the stream.
00686          */
00687         if(s->bytes_tracked > 0 && ubi_trCount(&s->data) > 1)
00688         {
00689             /* here we determine what we want to cut off */
00690             bytes_to_clear = (s->bytes_tracked / 100) * s4data.truncate_cut_off_perc;
00691 
00692             //DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00693             //printf("%5d -> %5d: stream_size: %5d: Going to try to truncate %d bytes (%d%%)\n", idx->client.port, idx->server.port, s->bytes_tracked, bytes_to_clear, s4data.truncate_cut_off_perc);
00694             //);
00695 
00696             SegmentTruncTraverse(s, bytes_to_clear);
00697 
00698             //printf("%5d -> %5d: stream_size: %5d\n", idx->client.port, idx->server.port, s->bytes_tracked);
00699         }
00700 
00701         /* only truncate the stream once this 'time'. */
00702         idx->server.last_trunc_time = thetime;
00703     }
00704 }
00705 
00706 int TruncHashTable(u_int32_t thetime, Session *save_me, int memCheck)
00707 {
00708     Session *idx = NULL, *savidx = NULL;
00709     u_int32_t pruned = 0;
00710     SFXHASH_NODE *lastNode = NULL;
00711 
00712 //    printf("%s: start (%u)\n", __FUNCTION__, stream4_memory_usage);
00713 
00714     if (thetime != 0)
00715     {
00716         char got_one;
00717         idx = (Session *) sfxhash_lru(sessionHashTable);
00718 
00719         if(idx == NULL)
00720         {
00721             return 0;
00722         }
00723 
00724         do
00725         {
00726             got_one = 0;            
00727             if(idx == save_me)
00728             {
00729 //                printf("%s: idx == save_me\n", __FUNCTION__);
00730 
00731                 lastNode = sfxhash_lru_node(sessionHashTable);
00732                 sfxhash_gmovetofront(sessionHashTable, lastNode);
00733                 lastNode = sfxhash_lru_node(sessionHashTable);
00734                 if ((lastNode) && (lastNode->data != idx))
00735                 {
00736                     idx = (Session *)lastNode->data;
00737                     continue;
00738                 }
00739                 else
00740                 {
00741                     return pruned;
00742                 }
00743             }
00744 
00745             /* check for stale sessions */
00746             if((idx->last_session_time+s4data.timeout) < thetime)
00747             {
00748 //                printf("%s: stale session\n", __FUNCTION__);
00749 
00750                 savidx = idx;
00751 
00752                 if(sfxhash_count(sessionHashTable) > 1)
00753                 {
00754                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning stale session\n"););
00755                     TruncSession(savidx, thetime);
00756                     idx = (Session *) sfxhash_lru(sessionHashTable);
00757                     pruned++;
00758                     got_one = 1;
00759 
00760                     if ((lastNode) && (lastNode->data))
00761                     {
00762                         idx = (Session *)lastNode->data;
00763                         continue;
00764                     }
00765                     else
00766                     {
00767                         return pruned;
00768                     }
00769                 }
00770                 else
00771                 {
00772                     TruncSession(savidx, thetime);
00773                     pruned++;
00774                     return pruned;
00775                 }
00776             }
00777             /* check for sessions that were not yet truncated this run */
00778             else if(    idx->server.last_trunc_time != thetime ||
00779                         idx->client.last_trunc_time != thetime)
00780             {
00781                 savidx = idx;
00782 
00783                 if(sfxhash_count(sessionHashTable) > 1)
00784                 {
00785                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning un-truncated session\n"););
00786                     TruncSession(savidx, thetime);
00787                     idx = (Session *) sfxhash_lru(sessionHashTable);
00788                     pruned++;
00789                     got_one = 1;
00790 
00791                     /* move the current node to the front, so our next
00792                        call returns another node. This is different from
00793                        CleanHashTable because there the last node is
00794                        removed */
00795                     lastNode = sfxhash_lru_node(sessionHashTable);
00796                     sfxhash_gmovetofront(sessionHashTable, lastNode);
00797                     lastNode = sfxhash_lru_node(sessionHashTable);
00798                     if ((lastNode) && (lastNode->data))
00799                     {
00800                         idx = (Session *)lastNode->data;
00801                         continue;
00802                     }
00803                     else
00804                     {
00805                         return pruned;
00806                     }
00807                 }
00808                 else
00809                 {
00810                     TruncSession(savidx, thetime);
00811                     pruned++;
00812                     return pruned;
00813                 }
00814             }
00815             else
00816             {
00817                 return pruned;
00818             }
00819         } while ((idx != NULL) && (got_one == 1));
00820 
00821         return pruned;
00822     }
00823     return pruned;
00824 }
00825 #endif /* USE_HASH_TABLE */
00826 #endif /* GIDS */
00827 
00828 
00829 #ifdef GIDS
00830 /* must be called with a non-nul 'thetime'.
00831 */
00832 int TruncSessionCache(u_int32_t thetime, int must_trunc, Session *save_me)
00833 {
00834 #ifdef USE_HASH_TABLE
00835     u_int32_t   cnt = 0;
00836 
00837     cnt = TruncHashTable(thetime, save_me, 0);
00838 //    printf("TruncHashTable truncated %u sessions.\n", cnt);
00839 #else /* SPLAY */
00840     Session *idx;
00841     Stream *s;
00842 //    BuildData bd;
00843     u_int16_t bytes_to_clear = 0;
00844 
00845     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TruncSessionCache starting... (%d sessions must be truncated, %lu sessions total)\n", must_trunc, ubi_trCount(RootPtr)););
00846 
00847     if(ubi_trCount(RootPtr) == 0)
00848     {
00849         return 0;
00850     }
00851 
00852     if(!must_trunc || !thetime)
00853     {
00854         return 0;
00855     }
00856 
00857     /* get the first session */
00858     idx = (Session *) ubi_btLeafNode((ubi_btNodePtr)RootPtr);
00859 
00860     while(must_trunc-- && ubi_trCount(RootPtr) > 1)
00861     {
00862         idx = (Session *) ubi_btNext((ubi_btNodePtr)idx);
00863 
00864         if(idx == NULL)
00865             break;
00866 
00867         if(idx != save_me)
00868         {
00869             /* only truncate the stream once this 'time'. */
00870 
00871             /* client */
00872             if(idx->client.last_trunc_time != thetime)
00873             {
00874                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TruncSessionCache: client: %d (%p).\n", idx->client.bytes_tracked, idx););
00875 
00876                 s = &idx->client;
00877 
00878                 /* only try to truncate if there is data in the stream
00879                  * and there is at least one spd in the stream.
00880                  */
00881                 if(s->bytes_tracked && ubi_trCount(&s->data) > 1)
00882                 {
00883                     /* here we determine what we want to cut off */
00884                     bytes_to_clear = s->bytes_tracked * (s4data.truncate_cut_off_perc / 100);
00885 
00886                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"%5d -> %5d: stream_size: %5d: Going to try to truncate %d bytes\n", idx->client.port, idx->server.port, s->bytes_tracked, bytes_to_clear););
00887 
00888                     /* walk the packet tree (in order) and try to cut off the
00889                      * ammount of bytes_to_clear */
00890                     SegmentTruncTraverse(s, bytes_to_clear);
00891                 }
00892                 
00893                 /* only truncate the stream once this 'time'. */
00894                 idx->client.last_trunc_time = thetime;
00895             }
00896             /* server */
00897             if(idx->server.last_trunc_time != thetime)
00898             {
00899                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TruncSessionCache: server: %d (%p).\n", idx->server.bytes_tracked, idx););
00900 
00901                 s = &idx->server;
00902 
00903                 /* only try to truncate if there is data in the stream
00904                  * and there is at least one spd in the stream.
00905                  */
00906                 if(s->bytes_tracked && ubi_trCount(&s->data) > 1)
00907                 {
00908                     /* here we determine what we want to cut off */
00909                     bytes_to_clear = s->bytes_tracked * (s4data.truncate_cut_off_perc / 100);
00910 
00911                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"%5d -> %5d: stream_size: %5d: Going to try to truncate %d bytes\n", idx->client.port, idx->server.port, s->bytes_tracked, bytes_to_clear););
00912 
00913                     /* walk the packet tree (in order) and try to cut off the
00914                      * ammount of bytes_to_clear */
00915                     SegmentTruncTraverse(s, bytes_to_clear);
00916                 }
00917                 
00918                 /* only truncate the stream once this 'time'. */
00919                 idx->server.last_trunc_time = thetime;
00920             }
00921         }
00922     }
00923 
00924 #ifdef DEBUG
00925     if(must_trunc)
00926     {
00927         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Truncated all sessions in the cache completely: must_trunc: %d, memusage: %u\n",must_trunc,stream4_memory_usage););
00928     }
00929 #endif /* DEBUG */
00930 
00931 #endif /* USE_HASH_TABLE */
00932     return 0;
00933 }
00934 
00935 
00936 #include "util.h"
00937 #include <errno.h>
00938 
00939 int DumpStateTable(const char *path)
00940 {
00941 #ifdef USE_HASH_TABLE
00942     Session *idx;
00943     u_int8_t tag = rand();
00944     char got_one = 1;
00945     Stream *client = NULL;
00946     Stream *server = NULL;
00947     SFXHASH_NODE *lastNode = NULL;
00948     struct in_addr sip, cip;
00949     char sipstr[16] = "", cipstr[16] = "";
00950     u_int32_t dumpcnt = 0,
00951               skipcnt = 0;
00952     FILE *fp = NULL;
00953 
00954     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"connections in hash: %u (path %s)\n", GetSessionCount(), path););
00955 
00956     idx = (Session *) sfxhash_lru(sessionHashTable);
00957     if(idx == NULL)
00958     {
00959         return 0;
00960     }
00961 
00962     if(path != NULL)
00963     {
00964         fp = fopen(path, "w+");
00965         if(fp == NULL)
00966         {
00967             FatalError("Opening '%s' failed: %s.\n", path, strerror(errno));
00968             return 0;
00969         }
00970         /* add a comment for the meaning of each field */
00971         fprintf(fp, "# state, start_time, last_session_time, client->ip, "
00972                     "client->port, client->isn, client->base_seq, "
00973                     "client->last_ack, client->win_size, client->pkts_sent, "
00974                     "client->bytes_sent server->ip, server->port, server->isn, "
00975                     "server->base_seq, server->last_ack, server->win_size, "
00976                     "server->pkts_sent, server->bytes_sent\n");
00977     }
00978 
00979     do
00980     {
00981         got_one = 0;            
00982 
00983         /* check if we already wrote this one to the file */
00984         if(idx->dumptag != tag)
00985         {
00986             got_one = 1;
00987 
00988             /* set our tag, so we won't handle it again this run */
00989             idx->dumptag = tag;
00990 
00991             client = &idx->client;
00992             server = &idx->server;
00993             
00994             /* path is NULL if we just want to print to screen */
00995             if(path == NULL)
00996             {
00997                 cip.s_addr = client->ip;
00998                 sip.s_addr = server->ip;
00999 
01000                 strlcpy(cipstr, inet_ntoa(cip), sizeof(cipstr));
01001                 strlcpy(sipstr, inet_ntoa(sip), sizeof(sipstr));
01002 
01003                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"connection %s:%u %s:%u\n",
01004                         cipstr, client->port, sipstr, server->port););
01005             }
01006             else
01007             {
01008                 if(idx->session_flags & SSNFLAG_ESTABLISHED ||
01009                    idx->session_flags & SSNFLAG_MIDSTREAM)
01010                 {
01011                     /* status */
01012                     if(idx->session_flags & SSNFLAG_ESTABLISHED)
01013                         fprintf(fp, "ESTABLISHED ");
01014                     else if(idx->session_flags & SSNFLAG_MIDSTREAM)
01015                         fprintf(fp, "MIDSTREAM ");
01016 
01017                     /* timeout */
01018                     fprintf(fp, "%u %u ", (u_int)idx->start_time,
01019                                           (u_int)idx->last_session_time);
01020 
01021                     /* client */
01022                     fprintf(fp, "%u %u %u %u %u %u %u %u ",
01023                         client->ip, client->port,
01024                         client->isn, client->base_seq, client->last_ack,
01025                         client->win_size, client->pkts_sent, client->bytes_sent);
01026 
01027                     /* server */
01028                     fprintf(fp, "%u %u %u %u %u %u %u %u ",
01029                         server->ip, server->port,
01030                         server->isn, server->base_seq, server->last_ack,
01031                         server->win_size, server->pkts_sent, server->bytes_sent);
01032 
01033                     fprintf(fp, "\n");
01034                 
01035                     dumpcnt++;
01036                 }
01037                 else
01038                 {
01039                     skipcnt++;
01040                 }
01041             }
01042 
01043             /* move the current node to the front, so our next
01044                call returns another node. This is different from
01045                CleanHashTable because there the last node is
01046                removed */
01047             lastNode = sfxhash_lru_node(sessionHashTable);
01048             sfxhash_gmovetofront(sessionHashTable, lastNode);
01049 
01050             idx = (Session *) sfxhash_lru(sessionHashTable);
01051         }
01052     } while((idx != NULL) && (got_one == 1));
01053 
01054     if(path != NULL)
01055     {
01056         fclose(fp);
01057         
01058         LogMessage("Dumped %u connections to the state file.\n", dumpcnt);
01059     }
01060 
01061     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"connections dumped: %u, skipped: %u, "
01062                             "total: %u\n", dumpcnt, skipcnt, dumpcnt+skipcnt););
01063     return 0;
01064 #else /* SPLAY */
01065     printf("%s only works with USE_HASH_TABLE enabled.\n", __FUNCTION__);
01066     return 0;
01067 #endif /* USE_HASH_TABLE */
01068 }
01069 
01070 #endif /* GIDS */

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