⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sfrt.c

📁 著名的入侵检测系统snort的最新版本的源码
💻 C
字号:
/**************************************************************************** * * Copyright (C) 2006-2007 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation.  You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************//* * @file    sfrt.c * @author  Adam Keeton <akeeton@sourcefire.com> * @date    Thu July 20 10:16:26 EDT 2006 * * Route implements two different routing table lookup mechanisms.  The table * lookups have been adapted to return a void pointer so any information can  * be associated with each CIDR block.   * * As of this writing, the two methods used are Stefan Nilsson and Gunnar  * Karlsson's LC-trie, and a multibit-trie method similar to Gupta et-al.'s  * DIR-n-m.  Presently, the LC-trie is used primarily for testing purposes as  * the current implementation does not allow for fast dynamic inserts. * * The intended use is for a user to optionally specify large IP blocks and  * then more specific information will be written into the routing tables  * from RNA.  Ideally, information will only move from less specific to more * specific.  If a more general information is to overwrite existing entries, * the table should be free'ed and rebuilt. *  * * Implementation: * * The routing tables associate an index into a "data" table with each CIDR.   * Each entry in the data table stores a pointer to actual data.  This  * implementation was chosen so each routing entry only needs one word to  * either index the data array, or point to another table.   * * Inserts are performed by specifying a CIDR and a pointer to its associated * data.  Since a new routing table entry may overwrite previous entries,  * a flag selects whether the insert favors the most recent or favors the most * specific.  Favoring most specific should be the default behvior.  If  * the user wishes to overwrite routing entries with more general data, the  * table should be flushed, rather than using favor-most-recent. *  * Before modifying the routing or data tables, the insert function performs a * lookup on the CIDR-to-be-insertted.  If no entry or an entry *of differing  * bit length* is found, the data is insertted into the data table, and its * index is used for the new routing table entry.  If an entry is found that  * is as specific as the new CIDR, the index stored points to where the new  * data is written into the data table. *  * If more specific CIDR blocks overwrote the data table, then the more  * general routing table entries that were not overwritten will be referencing * the wrong data.  Alternatively, less specific entries can only overwrite * existing routing table entries if favor-most-recent inserts are used. * * Because there is no quick way to clean the data-table if a user wishes to * use a favor-most-recent insert for more general data, the user should flush * the table with sfrt_free and create one anew.  Alternatively, a small  * memory leak occurs with the data table, as it will be storing pointers that * no routing table entry cares about. * * * The API calls that should be used are:  *  sfrt_new    - create new table *  sfrt_insert - insert entry  *  sfrt_lookup - lookup entry *  sfrt_free   - free table*/#include "sfrt.h"char *rt_error_messages[] = {   "Success",   "Insert Failure",   "Policy Table Exceeded",   "Dir Insert Failure",   "Dir Lookup Failure",   "Memory Allocation Failure"#ifdef SUPPORT_LCTRIE   ,   "LC Trie Compile Failure",   "LC Trie Insert Failure",   "LC Trie Lookup Failure"#endif};/* Create new lookup table  * @param   table_type Type of table. Uses the types enumeration in route.h  * @param   ip_type    IPv4 or IPv6. Uses the types enumeration in route.h  * @param   data_size  Max number of unique data entries * * Returns the new table. */table_t *sfrt_new(char table_type, char ip_type, long data_size, u_int32_t mem_cap) {    table_t *table = (table_t*)malloc(sizeof(table_t));    if(!table) {        return NULL;    }    /* IPv6 is not yet supported */    if(ip_type == IPv6) {        free(table);        return NULL;    }    /* If this limit is exceeded, there will be no way to distinguish     * between pointers and indeces into the data table.  Only     * applies to DIR-n-m. */#ifdef SUPPORT_LCTRIE#ifdef ULONGIS64BIT    if(data_size >= 0x800000000000000 && table_type == LCT) { #else    if(data_size >= 0x8000000 && table_type != LCT) { #endif#else /* SUPPORT_LCTRIE */#ifdef ULONGIS64BIT    if(data_size >= 0x800000000000000) {#else    if(data_size >= 0x8000000) {#endif#endif        free(table);        return NULL;    }    /* mem_cap is specified in megabytes, but internally uses bytes. Convert */    mem_cap *= 1024*1024;    /* Maximum allowable number of stored entries */    table->max_size = data_size;    table->data = (GENERIC*)calloc(sizeof(GENERIC) * table->max_size, 1);    if(!table->data) {        free(table);        return NULL;    }    table->allocated = sizeof(table_t) + sizeof(GENERIC) * table->max_size;    table->ip_type = ip_type;    table->table_type = table_type;    /* This will point to the actual table lookup algorithm */    table->rt = NULL;    /* index 0 will be used for failed lookups, so set this to 1 */    table->num_ent = 1;        switch(table_type) {#ifdef SUPPORT_LCTRIE        /* Setup LC-trie table */        case LCT:            /* LC trie is presently not allowed  */            table->insert = sfrt_lct_insert;            table->lookup = sfrt_lct_lookup;            table->free = sfrt_lct_free;            table->usage = sfrt_lct_usage;            table->rt = sfrt_lct_new(data_size);            free(table->data);            free(table);            return NULL;            break;#endif                    /* Setup DIR-n-m table */        case DIR_24_8:        case DIR_16x2:        case DIR_16_8x2:        case DIR_16_4x4:        case DIR_8x4:        case DIR_4x8:        case DIR_2x16:            table->insert = sfrt_dir_insert;            table->lookup = sfrt_dir_lookup;            table->free = sfrt_dir_free;            table->usage = sfrt_dir_usage;            break;        default:            free(table->data);            free(table);            return NULL;    };    /* Allocate the user-specified DIR-n-m table */    switch(table_type) {        case DIR_24_8:            table->rt = sfrt_dir_new(mem_cap, 2, 24,8);            break;        case DIR_16x2:            table->rt = sfrt_dir_new(mem_cap, 2, 16,16);            break;        case DIR_16_8x2:            table->rt = sfrt_dir_new(mem_cap, 3, 16,8,8);            break;        case DIR_16_4x4:            table->rt = sfrt_dir_new(mem_cap, 5, 16,4,4,4,4);            break;        case DIR_8x4:            table->rt = sfrt_dir_new(mem_cap, 4, 8,8,8,8);            break;        /* There is no reason to use 4x8 except for benchmarking and          * comparison purposes. */         case DIR_4x8:            table->rt = sfrt_dir_new(mem_cap, 8, 4,4,4,4,4,4,4,4);            break;        /* There is no reason to use 2x16 except for benchmarking and          * comparison purposes. */         case DIR_2x16:            table->rt = sfrt_dir_new(mem_cap, 16,                             2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2);            break;    };    if(!table->rt) {        free(table->data);        free(table);        return NULL;     }    return table;}/* Free lookup table */void sfrt_free(table_t *table) {    if(!table) {        /* What are you calling me for? */        return;    }    if(!table->data) {        /* This really really should not have happened */    } else {        free(table->data);    }    if(!table->rt) {        /* This should not have happened either */    } else {        table->free( table->rt );    }    free(table);}/* Perform a lookup on value contained in "ip" */GENERIC sfrt_lookup(void *adr, table_t* table) {    tuple_t tuple;    u_int32_t ip;    if(!adr) {        return NULL;    }    if(!table || !table->lookup) {        return NULL;    }    /* IPv6 not yet supported */    if(table->ip_type == IPv6) {        return NULL;    }    ip = *(u_int32_t*)adr;    tuple = table->lookup(ip, table->rt);    if(tuple.index >= table->num_ent) {        return NULL;    }    return table->data[tuple.index];}void sfrt_iterate(table_t* table, sfrt_iterator_callback userfunc){    u_int32_t index;    if (!table)        return;    for (index = 0; index < table->num_ent; index++)    {        if (table->data[index])            userfunc(table->data[index]);    }    return;}void sfrt_cleanup(table_t* table, sfrt_iterator_callback cleanup_func){    u_int32_t index;    if (!table)        return;    for (index = 0; index < table->num_ent; index++)    {        if (table->data[index])            cleanup_func(table->data[index]);        /* cleanup_func is supposed to free memory associated with this         * table->data[index].  Set that to NULL.         */        table->data[index] = NULL;    }    return;}/* Insert "ip", of length "len", into "table", and have it point to "ptr" *//* Insert "ip", of length "len", into "table", and have it point to "ptr" */int sfrt_insert(void *adr, unsigned char len, GENERIC ptr,					   int behavior, table_t *table) {    int index;    int res;    u_int32_t ip;    tuple_t tuple;     if(!adr) {        return RT_INSERT_FAILURE;    }    if(!table || !table->insert || !table->data || !table->lookup) {        return RT_INSERT_FAILURE;    }            /* IPv6 not yet supported */    if(table->ip_type == IPv6) {        return RT_INSERT_FAILURE;    }    if( (table->ip_type == IPv4 && len > 32) ||        (table->ip_type == IPv6 && len > 64) ) {        return RT_INSERT_FAILURE;    }    ip = *(u_int32_t*)adr;    /* Check if we can reuse an existing data table entry by      * seeing if there is an existing entry with the same length. */    /* Only perform this if the table is not an LC-trie */#ifdef SUPPORT_LCTRIE    if(table->table_type != LCT) {#endif        tuple = table->lookup(ip, table->rt);#ifdef SUPPORT_LCTRIE    }#endif#ifdef SUPPORT_LCTRIE    if(table->table_type == LCT || tuple.length != len) {#else    if(tuple.length != len) {#endif        if( table->num_ent >= table->max_size) {            return RT_POLICY_TABLE_EXCEEDED;         }        index = table->num_ent;        table->num_ent++;    }     else {        index = tuple.index;    }    /* Insert value into policy table */    table->data[ index ] = ptr;    /* The actual value that is looked-up is an index      * into the data table. */    res = table->insert(ip, len, index, behavior, table->rt);    /* Check if we ran out of memory. If so, need to decrement      * table->num_ent */    if(res == MEM_ALLOC_FAILURE) {        /* From the control flow above, it's possible table->num_ent was not         * incremented.  It should be safe to decrement here, because the only         * time it will be incremented above is when we are potentially          * mallocing one or more new entries (It's not incremented when we         * overwrite an existing entry). */        table->num_ent--;        }        return res;}u_int32_t sfrt_num_entries(table_t *table) {    if(!table || !table->rt || !table->allocated) {        return 0;    }        /* There is always a root node, so subtract 1 for it */    return table->num_ent - 1;}u_int32_t sfrt_usage(table_t *table) {    if(!table || !table->rt || !table->allocated || !table->usage) {        return 0;    }        return table->allocated + table->usage( table->rt );}#ifdef DEBUG_SFRT#define NUM_IPS 32#define NUM_DATA 4int main() {    table_t *dir;    u_int32_t ip_list[NUM_IPS];  /* entirely arbitrary */    char data[NUM_DATA];     /* also entirely arbitrary */    u_int32_t index, val;    for(index=0; index<NUM_IPS; index++) {        ip_list[index] = (u_int32_t)rand()%NUM_IPS;        data[index%NUM_DATA] = index%26 + 65;    /* Random letter */     }            dir = sfrt_new(DIR_16x2, IPv4, NUM_IPS, 20);    if(!dir) {        printf("Failed to create DIR\n");        return 1;    }    for(index=0; index < NUM_IPS; index++) {        if(sfrt_insert(&ip_list[index], 32, &data[index%NUM_DATA],                        RT_FAVOR_SPECIFIC, dir) != RT_SUCCESS) {            printf("DIR Insertion failure\n");            return 1;        }        printf("%d\t %x: %c -> %c\n", index, ip_list[index],               data[index%NUM_DATA], *(u_int32_t*)sfrt_lookup(&ip_list[index], dir));    }       for(index=0; index < NUM_IPS; index++) {        val = *(u_int32_t*)sfrt_lookup(&ip_list[index], dir);        printf("\t@%d\t%x: %c.  originally:\t%c\n",                             index, ip_list[index], val, data[index%NUM_DATA]);    }       printf("Usage: %d bytes\n", ((dir_table_t*)(dir->rt))->allocated);        sfrt_free(dir);    return 0;}#endif /* DEBUG_SFRT */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -