diff --git a/src/Makefile.am b/src/Makefile.am index 6470688eb6..af85d3608a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,6 +33,7 @@ flow-bit.c flow-bit.h \ flow-alert-sid.c flow-alert-sid.h \ pkt-var.c pkt-var.h \ host.c host.h \ +reputation.c reputation.h \ detect.c detect.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine.c detect-engine.h \ diff --git a/src/reputation.c b/src/reputation.c new file mode 100644 index 0000000000..eceb7db103 --- /dev/null +++ b/src/reputation.c @@ -0,0 +1,1448 @@ +/** + * Copyright (c) 2009 Open Information Security Foundation + * + * \author Pablo Rincon Crespo + * Idea by Matt Jonkman + * + * IP Reputation Module, initial API for IPV4 and IPV6 feed + * + */ + +#include "util-error.h" +#include "util-debug.h" +#include "util-radix-tree.h" +#include "reputation.h" +#include "util-host-os-info.h" +#include "util-unittest.h" +#include "suricata-common.h" +#include "threads.h" + +/** Global trees that hold host reputation for IPV4 and IPV6 hosts */ +IPReputationCtx *rep_ctx; + +/** + * \brief Initialization fuction for the Reputation Context (IPV4 and IPV6) + * + * \retval Pointer to the IPReputationCtx created + * NULL Error initializing moule; + */ +IPReputationCtx *SCReputationInitCtx() { + rep_ctx = (IPReputationCtx *)malloc(sizeof(IPReputationCtx)); + if (rep_ctx == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for Reputation context"); + exit(EXIT_FAILURE); + } + memset(rep_ctx,0,sizeof(IPReputationCtx)); + + rep_ctx->reputationIPV4_tree = SCRadixCreateRadixTree(SCReputationFreeData); + if (rep_ctx->reputationIPV4_tree == NULL) { + SCLogDebug("Error initializing Reputation IPV4 module"); + return NULL; + } + + SCLogDebug("Reputation IPV4 module initialized"); + + rep_ctx->reputationIPV6_tree = SCRadixCreateRadixTree(SCReputationFreeData); + if (rep_ctx->reputationIPV6_tree == NULL) { + SCLogDebug("Error initializing Reputation IPV6 module"); + return NULL; + } + + SCLogDebug("Reputation IPV6 module initialized"); + if (SCMutexInit(&rep_ctx->reputationIPV4_lock, NULL) != 0) { + SCLogError(SC_ERR_MUTEX, "Mutex not correctly initialized"); + exit(EXIT_FAILURE); + } + if (SCMutexInit(&rep_ctx->reputationIPV6_lock, NULL) != 0) { + SCLogError(SC_ERR_MUTEX, "Mutex not correctly initialized"); + exit(EXIT_FAILURE); + } + + return rep_ctx; +} + + +/** + * \brief Allocates the Reputation structure for a host/netblock + * + * \retval rep_data On success, pointer to the rep_data that has to be sent + * along with the key, to be added to the Radix tree + */ +Reputation *SCReputationAllocData() +{ + Reputation *rep_data = NULL; + + if ( (rep_data = malloc(sizeof(Reputation))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + memset(rep_data,0, sizeof(Reputation)); + rep_data->ctime = time(NULL); + rep_data->mtime= time(NULL); + + return rep_data; +} + +/** + * \brief Used to free the reputation data that is allocated by Reputation API + * + * \param Pointer to the data that has to be freed + */ +void SCReputationFreeData(void *data) +{ + if (data != NULL) + free(data); + + return; +} + +/** + * \brief Allocates the Reputation structure for a host/netblock + * + * \retval ReputationTransaction pointer On success + */ +ReputationTransaction *SCReputationTransactionAlloc() +{ + ReputationTransaction *rtx = NULL; + + if ( (rtx = malloc(sizeof(ReputationTransaction))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + memset(rtx, 0, sizeof(ReputationTransaction)); + + return rtx; +} + +/** + * \brief Used to free the transaction data + * + * \param Pointer to the data that has to be freed + */ +void SCReputationTransactionFreeData(void *data) +{ + if (data != NULL) + free(data); + + return; +} + +/** + * \brief Apply the transaction of changes to the reputation + * We use transactions because we cant be locking/unlocking the + * trees foreach update. This help for a better performance + * + * \param rep_data pointer to the reputation to update + * \param rtx pointer to the transaction data + */ +void SCReputationApplyTransaction(Reputation *rep_data, ReputationTransaction *rtx) { + int i = 0; + + /* No modification needed */ + if ( !(rtx->flags & TRANSACTION_FLAG_NEEDSYNC)) + return; + + /* Here we should apply a formula, a threshold or similar, + * maybe values loaded from config */ + for (; i < REPUTATION_NUMBER; i++) { + if (rtx->flags & TRANSACTION_FLAG_INCS) { + if (rep_data->reps[i] + rtx->inc[i] < 255) + rep_data->reps[i] += rtx->inc[i]; + else + rep_data->reps[i] = 255; + } + if (rtx->flags & TRANSACTION_FLAG_DECS) { + if (rep_data->reps[i] - rtx->dec[i] > 0) + rep_data->reps[i] -= rtx->dec[i]; + else + rep_data->reps[i] = 0; + } + } + rep_data->mtime = time(NULL); + rep_data->flags |= REPUTATION_FLAG_NEEDSYNC; +} + +/** + * \brief Function that compare two reputation structs to determine if they are equal + * + * \param rep1 pointer to reputation 1 + * \param rep2 pointer to reputation 2 + * + * \retval 1 if they are equal; 0 if not + */ +int SCReputationEqual(Reputation *rep1, Reputation *rep2) +{ + return (memcmp(rep1->reps, rep2->reps, REPUTATION_NUMBER * sizeof(uint8_t)) == 0)? 1 : 0; +} + + +/** + * \brief Helper function to print the Reputation structure + * + * \param Pointer rep_data to a Reputation structure + */ +void SCReputationPrint(Reputation *rep_data) +{ + if (rep_data == NULL) { + printf("No Reputation Data!\n"); + return; + } + int i = 0; + for (; i < REPUTATION_NUMBER; i++) + printf("Rep_type %d = %d\n", i, rep_data->reps[i]); + + if (rep_data->flags & REPUTATION_FLAG_NEEDSYNC) + printf("REPUTATION_FLAG_NEEDSYNC = 1\n"); +} + +/** + * \brief Clone all the data of a reputation + * When you try to update the feed, if the data you have belongs + * to a netblock, it will be cloned and inserted or a host, with + * the modifications that you add + * + * \param orig Pointer to the original reputation (probably of a netblock) + * + * \retval Reputation Pointer to the reputation copy + */ +Reputation *SCReputationClone(Reputation *orig) +{ + Reputation *rep = NULL; + if (orig == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return NULL; + } + + if ( (rep = malloc(sizeof(Reputation))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + memcpy(rep, orig, sizeof(Reputation)); + return rep; +} + +void SCReputationFreeCtx() +{ + if (rep_ctx->reputationIPV4_tree != NULL) { + SCRadixReleaseRadixTree(rep_ctx->reputationIPV4_tree); + rep_ctx->reputationIPV4_tree = NULL; + SCMutexDestroy(&rep_ctx->reputationIPV4_lock); + } + if (rep_ctx->reputationIPV6_tree != NULL) { + SCRadixReleaseRadixTree(rep_ctx->reputationIPV6_tree); + rep_ctx->reputationIPV6_tree = NULL; + SCMutexDestroy(&rep_ctx->reputationIPV6_lock); + } +} + +/** + * \brief Used to add a new reputation to the reputation module (only at the startup) + * + * \param ipv4addr pointer to the ipv4 address key + * \param netmask_value of the ipv4 address (can be a subnet or a host (32)) + * \param rep_data Reputation pointer to the Reputation associated to the host/net + * + * \retval NULL On failure; rep_data on success + */ +Reputation *SCReputationAddIPV4Data(uint8_t *ipv4addr, int netmask_value, Reputation *rep_data) +{ + struct in_addr *ipv4_addr = (struct in_addr *) ipv4addr; + + if (ipv4_addr == NULL || rep_data == NULL || rep_ctx == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return NULL; + } + + /* If the reputation tree is not initialized yet */ + if (rep_ctx->reputationIPV4_tree == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Reputation trees not initialized"); + return NULL; + } + + if (netmask_value == 32) { + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, + (void *)rep_data); + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); + + } else { + if (netmask_value < 0 || netmask_value > 31) { + SCLogError(SC_INVALID_IP_NETBLOCK, "Invalid IPV4 Netblock"); + return NULL; + } + + SCRadixChopIPAddressAgainstNetmask((uint8_t *)ipv4_addr, netmask_value, 32); + + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + SCRadixAddKeyIPV4Netblock((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, + (void *)rep_data, netmask_value); + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); + } + + return rep_data; +} + +/** + * \brief Retrieves the Reputation of a host (exact match), given an ipv4 address in the raw + * address format. + * + * \param ipv4_addr Pointer to a raw ipv4 address. + * + * \retval Pointer to a copy of the host Reputation on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV4ExactMatch(uint8_t *ipv4_addr) +{ + Reputation *rep_data; + + /* Be careful with this (locking)*/ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + + SCRadixNode *node = SCRadixFindKeyIPV4ExactMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + rep_data = NULL; + } else { + /* Yes, we clone it because the pointer can be outdated + * while another thread remove this reputation */ + rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); + } + + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); + return rep_data; +} + +/** + * \brief Retrieves the Reputation of a host (best match), given an ipv4 address in the raw + * address format. + * + * \param ipv4_addr Pointer to a raw ipv4 address. + * + * \retval Pointer to a copy of the host Reputation on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV4BestMatch(uint8_t *ipv4_addr) +{ + Reputation *rep_data; + + /* Be careful with this (locking)*/ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + + SCRadixNode *node = SCRadixFindKeyIPV4BestMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + rep_data = NULL; + } else { + /* Yes, we clone it because the pointer can be outdated + * while another thread remove this reputation */ + rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); + } + + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); + return rep_data; +} + +/** + * \brief Retrieves the Reputation of a host (best match), given an ipv6 address in the raw + * address format. + * + * \param Pointer to a raw ipv6 address. + * + * \retval Pointer to a copy of the host Reputation on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV6BestMatch(uint8_t *ipv6_addr) +{ + Reputation *rep_data; + + /* Be careful with this (locking)*/ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + + SCRadixNode *node = SCRadixFindKeyIPV6BestMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + rep_data = NULL; + } else { + /* Yes, we clone it because the pointer can be outdated + * while another thread remove this reputation */ + rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); + } + + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); + return rep_data; +} + +/** + * \brief Retrieves the Reputation of a host (exact match), given an ipv6 address in the raw + * address format. + * + * \param Pointer to a raw ipv6 address. + * + * \retval Pointer to a copy of the host reputation on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV6ExactMatch(uint8_t *ipv6_addr) +{ + Reputation *rep_data; + + /* Be careful with this (locking)*/ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + + SCRadixNode *node = SCRadixFindKeyIPV6ExactMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + rep_data = NULL; + } else { + /* Yes, we clone it because the pointer can be outdated + * while another thread remove this reputation */ + rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); + } + + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); + return rep_data; +} + + +/** + * \brief Retrieves the Real Reputation of a host (exact match), given an ipv4 address in the raw + * address format. (Not thread safe!) + * + * \param ipv4_addr Pointer to a raw ipv4 address. + * + * \retval Pointer to the Reputation of the host on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV4ExactMatchReal(uint8_t *ipv4_addr) +{ + SCRadixNode *node = SCRadixFindKeyIPV4ExactMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + return NULL; + } else { + return (Reputation *)node->prefix->user_data_result; + } +} + +/** + * \brief Retrieves the Real Reputation of a host (best match), given an ipv4 address in the raw + * address format. (Not thread safe!) + * + * \param ipv4_addr Pointer to a raw ipv4 address. + * + * \retval Pointer to the Reputation of the host on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV4BestMatchReal(uint8_t *ipv4_addr) +{ + SCRadixNode *node = SCRadixFindKeyIPV4BestMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + return NULL; + } else { + return (Reputation *)node->prefix->user_data_result; + } +} + +/** + * \brief Retrieves the Real Reputation of a host (best match), given an ipv6 address in the raw + * address format. (Not thread safe!) + * + * \param Pointer to a raw ipv6 address. + * + * \retval Pointer to the Reputation of the host on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV6BestMatchReal(uint8_t *ipv6_addr) +{ + SCRadixNode *node = SCRadixFindKeyIPV6BestMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + return NULL; + } else { + return (Reputation *)node->prefix->user_data_result; + } +} + +/** + * \brief Retrieves the Real Reputation of a host (exact match), given an ipv6 address in the raw + * address format. (Not thread safe!) + * + * \param Pointer to a raw ipv6 address. + * + * \retval Pointer to the Reputation of the host on success; + * NULL on failure, or on not finding the key; + */ +Reputation *SCReputationLookupIPV6ExactMatchReal(uint8_t *ipv6_addr) +{ + SCRadixNode *node = SCRadixFindKeyIPV6ExactMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); + if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { + return NULL; + } else { + return (Reputation *)node->prefix->user_data_result; + } +} + +/** + * \brief Remove the node of the reputation tree associated to the ipv4 address + * + * \param ipv4_addr Pointer to a raw ipv4 address + * \param netmask_value netmask to apply to the address (32 for host) + * + */ +void SCReputationRemoveIPV4Data(uint8_t * ipv4_addr, uint8_t netmask_value) +{ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + SCRadixRemoveKeyIPV4Netblock(ipv4_addr, rep_ctx->reputationIPV4_tree, netmask_value); + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); +} + +/** + * \brief Remove the node of the reputation tree associated to the ipv6 address + * + * \param ipv6_addr Pointer to a raw ipv6 address + * \param netmask_value netmask to apply to the address (128 for host) + * + */ +void SCReputationRemoveIPV6Data(uint8_t * ipv6_addr, uint8_t netmask_value) +{ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + SCRadixRemoveKeyIPV6Netblock(ipv6_addr, rep_ctx->reputationIPV6_tree, netmask_value); + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); +} + +/** + * \brief Used to add a new reputation to the reputation module (only at the startup) + * + * \param ipv6addr pointer to the ipv6 address key + * \param netmask_value of the ipv6 address (can be a subnet) + * \param rep_data Reputation pointer to the Reputation associated to the host/net + * + * \retval NULL On failure + */ +Reputation *SCReputationAddIPV6Data(uint8_t *ipv6addr, int netmask_value, Reputation *rep_data) +{ + struct in_addr *ipv6_addr = (struct in_addr *) ipv6addr; + + if (ipv6_addr == NULL || rep_data == NULL || rep_ctx == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return NULL; + } + + /* If the reputation tree is not initialized yet */ + if (rep_ctx->reputationIPV6_tree == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Reputation trees not initialized"); + return NULL; + } + + if (netmask_value == 128) { + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, + (void *)rep_data); + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); + + } else { + if (netmask_value < 0 || netmask_value > 127) { + SCLogError(SC_INVALID_IP_NETBLOCK, "Invalid IPV6 Netblock"); + return NULL; + } + + SCRadixChopIPAddressAgainstNetmask((uint8_t *)ipv6_addr, netmask_value, 128); + + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, + (void *)rep_data, netmask_value); + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); + } + + return rep_data; +} + +/** + * \brief Update a reputation or insert a new one. If it doesn't exist + * it will try to search for the reputation of parent subnets to + * create the new reputation data based on this one + * + * \param ipv6addr pointer to the ipv6 address key + * \param rep_data Reputation pointer to the Reputation associated to the host/net + * + * \retval NULL On failure + */ +Reputation *SCReputationUpdateIPV4Data(uint8_t *ipv4addr, ReputationTransaction *rtx) +{ + struct in_addr *ipv4_addr = (struct in_addr *) ipv4addr; + Reputation *actual_rep; + + if (ipv4_addr == NULL || rtx == NULL || rep_ctx == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return NULL; + } + + /* If the reputation tree is not initialized yet */ + if (rep_ctx->reputationIPV4_tree == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Reputation trees not initialized"); + return NULL; + } + + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV4_lock); + + /* Search exact match and update */ + actual_rep = SCReputationLookupIPV4ExactMatchReal(ipv4addr); + if (actual_rep == NULL) { + /* else search best match (parent subnets) */ + actual_rep =SCReputationLookupIPV4BestMatchReal(ipv4addr); + + if (actual_rep != NULL) { + /* clone from parent and insert host */ + actual_rep = SCReputationClone(actual_rep); + } else { + /* else insert a new reputation data for the host */ + actual_rep = SCReputationAllocData(); + /* If new, we only increment values */ + rtx->flags = TRANSACTION_FLAG_INCS; + rtx->flags |= TRANSACTION_FLAG_NEEDSYNC; + } + + /* insert the reputation data in the tree */ + SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, + (void *)actual_rep); + } + /* Apply updates */ + SCReputationApplyTransaction(actual_rep, rtx); + + /* Unlock! */ + SCMutexUnlock(&rep_ctx->reputationIPV4_lock); + + return actual_rep; +} + +/** + * \brief Update a reputation or insert a new one. If it doesn't exist + * it will try to search for the reputation of parent subnets to + * create the new reputation data based on this one + * + * \param ipv6addr pointer to the ipv6 address key + * \param rep_data Reputation pointer to the Reputation associated to the host/net + * + * \retval NULL On failure + */ +Reputation *SCReputationUpdateIPV6Data(uint8_t *ipv6addr, ReputationTransaction *rtx) +{ + struct in_addr *ipv6_addr = (struct in_addr *) ipv6addr; + Reputation *actual_rep; + + if (ipv6_addr == NULL || rtx == NULL || rep_ctx == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return NULL; + } + + /* If the reputation tree is not initialized yet */ + if (rep_ctx->reputationIPV6_tree == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Reputation trees not initialized"); + return NULL; + } + + /* Be careful with the mutex */ + SCMutexLock(&rep_ctx->reputationIPV6_lock); + + /* Search exact match and update */ + actual_rep = SCReputationLookupIPV6ExactMatchReal(ipv6addr); + if (actual_rep == NULL) { + /* else search best match (parent subnets) */ + actual_rep =SCReputationLookupIPV6BestMatchReal(ipv6addr); + + if (actual_rep != NULL) { + /* clone from parent and insert host */ + actual_rep = SCReputationClone(actual_rep); + } else { + /* else insert a new reputation data for the host */ + actual_rep = SCReputationAllocData(); + /* If new, we only increment values */ + rtx->flags = TRANSACTION_FLAG_INCS; + rtx->flags |= TRANSACTION_FLAG_NEEDSYNC; + } + + /* insert the reputation data in the tree */ + SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, + (void *)actual_rep); + } + /* Apply updates */ + SCReputationApplyTransaction(actual_rep, rtx); + + /* Unlock! */ + SCMutexUnlock(&rep_ctx->reputationIPV6_lock); + + return actual_rep; +} + + +/* ----------------- UNITTESTS-------------------- */ +#ifdef UNITTESTS + +/** + * \test Adding (from numeric ipv4) and removing host reputation in the Reputation context + * tree. THe reputation data is the real one, no copies here. + */ +int SCReputationTestIPV4AddRemoveHost01() +{ + int i = 0; + struct in_addr in; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 6; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); + if (rep_orig == NULL) + goto error; + + Reputation *rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_orig) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_orig) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 31, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data == NULL || rep_data == rep_orig) + goto error; + + if (inet_pton(AF_INET, "192.168.1.8", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data != NULL) + goto error; + + + /* Removing */ + if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) + goto error; + + SCReputationRemoveIPV4Data((uint8_t *) &in, 32); + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) + goto error; + + SCReputationRemoveIPV4Data((uint8_t *) &in, 32); + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV4_tree); + + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Adding (from numeric ipv6) and removing host reputation in the Reputation context + * tree. THe reputation data is the real one, no copies here. + */ +int SCReputationTestIPV6AddRemoveHost01() +{ + uint8_t in[16]; + uint8_t i = 0; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) + goto error; + + Reputation *rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 1; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); + if (rep_orig == NULL) + goto error; + + Reputation *rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_orig) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 8; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + + if (rep_data == NULL || rep_data != rep_orig) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 127, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data == NULL || rep_data == rep_orig) + goto error; + + + /* Removing */ + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) + goto error; + + SCReputationRemoveIPV6Data((uint8_t *) &in, 128); + + rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) + goto error; + + SCReputationRemoveIPV6Data((uint8_t *) &in, 128); + rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV6_tree); + + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Adding (from numeric ipv4) and retrieving reputations + * tree. The reputation data retireved are copies of the original. + */ +int SCReputationTestIPV4AddRemoveHost02() +{ + int i = 0; + struct in_addr in; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 6; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); + if (rep_orig == NULL) + goto error; + + Reputation *rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 9; + + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 31, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 1) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV4_tree); + + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Adding (from numeric ipv6) and removing host reputation in the Reputation context + * tree. The reputation data retireved are copies of the original. + */ +int SCReputationTestIPV6AddRemoveHost02() +{ + int i = 0; + uint8_t in[16]; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 6; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); + if (rep_orig == NULL) + goto error; + + Reputation *rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 9; + + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 127, rep_orig); + if (rep_orig == NULL) + goto error; + + rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 1) + goto error; + + if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2364", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); + /* It should return the host info and not the subnet info */ + if (rep_data != NULL) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV6_tree); + + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Test searches (best and exact matches) + */ +int SCReputationTestIPV4BestExactMatch01() +{ + int i = 0; + struct in_addr in; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_origC = NULL; + Reputation *rep_origB = NULL; + Reputation *rep_origA = NULL; + + Reputation *rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 6; + + /* adding a host */ + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); + if (rep_orig == NULL) + goto error; + Reputation *rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_orig) + goto error; + + rep_orig = SCReputationAllocData(); + if (rep_orig == NULL) + goto error; + + /* Adding C subnet */ + if (inet_pton(AF_INET, "192.168.1.0", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_origC = SCReputationAddIPV4Data((uint8_t *) &in, 24, rep_orig); + if (rep_origC == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origC) + goto error; + + rep_orig = SCReputationAllocData(); + /* Adding B subnet */ + if (inet_pton(AF_INET, "192.168.0.0", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_origB = SCReputationAddIPV4Data((uint8_t *) &in, 16, rep_orig); + if (rep_origB == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origC) + goto error; + + if (inet_pton(AF_INET, "192.168.2.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origB) + goto error; + + rep_orig = SCReputationAllocData(); + /* Adding A subnet */ + if (inet_pton(AF_INET, "192.0.0.0", &in) < 0) + goto error; + + for (i = 0; i < REPUTATION_NUMBER; i++) + rep_orig->reps[i] = i * 10 + 7; + + rep_origA = SCReputationAddIPV4Data((uint8_t *) &in, 8, rep_orig); + if (rep_origA == NULL) + goto error; + + if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origC) + goto error; + + if (inet_pton(AF_INET, "192.168.2.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origB) + goto error; + + if (inet_pton(AF_INET, "192.167.2.5", &in) < 0) + goto error; + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data != NULL) + goto error; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || rep_data != rep_origA) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV4_tree); + + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Update transactions + */ +int SCReputationTestIPV4Update01() +{ + int i = 0; + struct in_addr in; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_orig = SCReputationAllocData(); + + ReputationTransaction rtx; + memset(&rtx, 0, sizeof(ReputationTransaction)); + if (rep_orig == NULL) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) { + rep_orig->reps[i] = 10; + } + + if (inet_pton(AF_INET, "192.168.0.0", &in) < 0) + goto error; + + /* Add add it as net */ + rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 16, rep_orig); + if (rep_orig == NULL) + goto error; + + rtx.dec[REPUTATION_DDOS] = 5; + rtx.inc[REPUTATION_PHISH] = 50; + rtx.inc[REPUTATION_MALWARE] = 30; + rtx.flags |= TRANSACTION_FLAG_NEEDSYNC; + rtx.flags |= TRANSACTION_FLAG_INCS; + rtx.flags |= TRANSACTION_FLAG_DECS; + + if (inet_pton(AF_INET, "192.168.10.100", &in) < 0) + goto error; + + /* Update (it will create the host entry with the data of the net) */ + SCReputationUpdateIPV4Data((uint8_t *)&in, &rtx); + + /* Create the reputation that any host 192.168.* should have */ + Reputation *rep_aux = SCReputationAllocData(); + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) { + rep_aux->reps[i] = 10; + } + + rep_aux->reps[REPUTATION_DDOS] = 5; + rep_aux->reps[REPUTATION_PHISH] = 60; + rep_aux->reps[REPUTATION_MALWARE] = 40; + + Reputation *rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + /* Now that is created, it should update only the host */ + rtx.dec[REPUTATION_DDOS] = 50; + rtx.inc[REPUTATION_PHISH] = 50; + rtx.inc[REPUTATION_MALWARE] = 50; + + rep_aux->reps[REPUTATION_DDOS] = 0; + rep_aux->reps[REPUTATION_PHISH] = 110; + rep_aux->reps[REPUTATION_MALWARE] = 90; + + SCReputationUpdateIPV4Data((uint8_t *)&in, &rtx); + + rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + /* So let's see if we add a host and get the parent data again */ + if (inet_pton(AF_INET, "192.168.10.101", &in) < 0) + goto error; + + rep_aux->reps[REPUTATION_DDOS] = 10; + rep_aux->reps[REPUTATION_PHISH] = 10; + rep_aux->reps[REPUTATION_MALWARE] = 10; + + rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); + + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV4_tree); + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +/** + * \test Update transactions + */ +int SCReputationTestIPV6Update01() +{ + int i = 0; + uint8_t in[16]; + + SCReputationInitCtx(); + if (rep_ctx == NULL) { + SCLogInfo("Error initializing Reputation Module"); + return 0; + } + + Reputation *rep_orig = SCReputationAllocData(); + + ReputationTransaction rtx; + memset(&rtx, 0, sizeof(ReputationTransaction)); + if (rep_orig == NULL) + goto error; + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) { + rep_orig->reps[i] = 10; + } + + if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1DDD", &in) < 0) + goto error; + + /* Add add it as net */ + rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 98, rep_orig); + if (rep_orig == NULL) + goto error; + + rtx.dec[REPUTATION_DDOS] = 5; + rtx.inc[REPUTATION_PHISH] = 50; + rtx.inc[REPUTATION_MALWARE] = 30; + rtx.flags |= TRANSACTION_FLAG_NEEDSYNC; + rtx.flags |= TRANSACTION_FLAG_INCS; + rtx.flags |= TRANSACTION_FLAG_DECS; + + if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1ABA", &in) < 0) + goto error; + + /* Update (it will create the host entry with the data of the net) */ + SCReputationUpdateIPV6Data((uint8_t *)&in, &rtx); + + /* Create the reputation that any host 192.168.* should have */ + Reputation *rep_aux = SCReputationAllocData(); + + /* Fill the reputation with some values.. */ + for (i = 0; i < REPUTATION_NUMBER; i++) { + rep_aux->reps[i] = 10; + } + + rep_aux->reps[REPUTATION_DDOS] = 5; + rep_aux->reps[REPUTATION_PHISH] = 60; + rep_aux->reps[REPUTATION_MALWARE] = 40; + + Reputation *rep_data = SCReputationLookupIPV6BestMatchReal((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + /* Now that is created, it should update only the host */ + rtx.dec[REPUTATION_DDOS] = 50; + rtx.inc[REPUTATION_PHISH] = 50; + rtx.inc[REPUTATION_MALWARE] = 50; + + rep_aux->reps[REPUTATION_DDOS] = 0; + rep_aux->reps[REPUTATION_PHISH] = 110; + rep_aux->reps[REPUTATION_MALWARE] = 90; + + SCReputationUpdateIPV6Data((uint8_t *)&in, &rtx); + + rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + /* So let's see if we add a host and get the parent data again */ + if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1ACB", &in) < 0) + goto error; + + rep_aux->reps[REPUTATION_DDOS] = 10; + rep_aux->reps[REPUTATION_PHISH] = 10; + rep_aux->reps[REPUTATION_MALWARE] = 10; + + rep_data = SCReputationLookupIPV6BestMatchReal((uint8_t *) &in); + + + if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) + goto error; + + SCRadixPrintTree(rep_ctx->reputationIPV6_tree); + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 1; + +error: + SCReputationFreeCtx(rep_ctx); + rep_ctx = NULL; + return 0; +} + +#endif /* UNITTESTS */ + +/** Register the following unittests for the Reputation module */ +void SCReputationRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCReputationTestIPV4AddRemoveHost01", + SCReputationTestIPV4AddRemoveHost01, 1); + UtRegisterTest("SCReputationTestIPV6AddRemoveHost01", + SCReputationTestIPV6AddRemoveHost01, 1); + + UtRegisterTest("SCReputationTestIPV4BestExactMatch01", + SCReputationTestIPV4BestExactMatch01, 1); + + UtRegisterTest("SCReputationTestIPV4AddRemoveHost02", + SCReputationTestIPV4AddRemoveHost02, 1); + UtRegisterTest("SCReputationTestIPV6AddRemoveHost02", + SCReputationTestIPV6AddRemoveHost02, 1); + + UtRegisterTest("SCReputationTestIPV4Update01", + SCReputationTestIPV4Update01, 1); + UtRegisterTest("SCReputationTestIPV6Update01", + SCReputationTestIPV6Update01, 1); +#endif /* UNITTESTS */ +} + diff --git a/src/reputation.h b/src/reputation.h index 9751654584..506d5dc58a 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -1,14 +1,19 @@ -#ifndef __REPUTATION_H__ -#define __REPUTATION_H__ - -/** \file - * \author Victor Julien +/** + * Copyright (c) 2009 Open Information Security Foundation + * + * \author Pablo Rincon Crespo + * \author Victor Julien + * Original Idea by Matt Jonkman * * General reputation for ip's (ipv4/ipv6) and (maybe later) host names */ -/* Reputation numbers that we can use to lookup the reps in an array */ +#ifndef __REPUTATION_H__ +#define __REPUTATION_H__ +/** Reputation numbers (types) that we can use to lookup/update, etc + * Please, dont convert this to a enum since we want the same reputation + * codes always. */ #define REPUTATION_SPAM 0 /**< spammer */ #define REPUTATION_CNC 1 /**< CnC server */ #define REPUTATION_SCAN 2 /**< scanner */ @@ -18,20 +23,60 @@ #define REPUTATION_PROXY 6 /**< known tor out nodes, proxy servers, etc */ #define REPUTATION_P2P 7 /**< Heavy p2p node, torrent server, other sharing services */ #define REPUTATION_UTILITY 8 /**< known good places like google, yahoo, msn.com, etc */ -#define REPUTATION_DDOS 9 /**< Known ddos participant. */ -#define REPUTATION_PHISH 10 /**< Known Phishing site. */ -#define REPUTATION_MALWARE 11 /**< Known Malware distribution site. (Hacked web server etc) */ -#define REPUTATION_ZOMBIE 12 /**< Known Zombie (botnet member) (They typically are Scanner or Hostile, +#define REPUTATION_DDOS 9 /**< Known ddos participant */ +#define REPUTATION_PHISH 10 /**< Known Phishing site */ +#define REPUTATION_MALWARE 11 /**< Known Malware distribution site. Hacked web server, etc */ +#define REPUTATION_ZOMBIE 12 /**< Known Zombie (botnet member) They typically are Scanner or Hostile, but if collaboration with botnet snooping, like we did back in 2005 or so, can proactively identify online zombies that joined a - botnet, you may want to break those out separately.) */ -#define REPUTATION_NUMBER 13 /**< number of rep types we have for data structure size */ + botnet, you may want to break those out separately */ +#define REPUTATION_NUMBER 13 /**< number of rep types we have for data structure size (be careful with this) */ + +/* Flags for reputation */ #define REPUTATION_FLAG_NEEDSYNC 0x01 /**< rep was changed by engine, needs sync with external hub */ +/** Reputation Context for IPV4 IPV6 */ +typedef struct IPReputationCtx_ { + /** Radix trees that holds the host reputation information */ + SCRadixTree *reputationIPV4_tree; + SCRadixTree *reputationIPV6_tree; + + /** Mutex to support concurrent access */ + SCMutex reputationIPV4_lock; + SCMutex reputationIPV6_lock; +}IPReputationCtx; + +/** Reputation Data */ +//TODO: Add a timestamp here to know the last update of this reputation. typedef struct Reputation_ { uint8_t reps[REPUTATION_NUMBER]; /**< array of 8 bit reputations */ uint8_t flags; /**< reputation flags */ + time_t ctime; /**< creation time (epoch) */ + time_t mtime; /**< modification time (epoch) */ } Reputation; +/* flags for transactions */ +#define TRANSACTION_FLAG_NEEDSYNC 0x01 /**< We will apply the transaction only if necesary */ +#define TRANSACTION_FLAG_INCS 0x02 /**< We will increment only if necesary */ +#define TRANSACTION_FLAG_DECS 0x03 /**< We will decrement only if necesary */ + +/* transaction for feedback */ +typedef struct ReputationTransaction_ { + uint16_t inc[REPUTATION_NUMBER]; + uint16_t dec[REPUTATION_NUMBER]; + uint8_t flags; +}ReputationTransaction; + +/* API */ +Reputation *SCReputationAllocData(); +Reputation *SCReputationClone(Reputation *); +void SCReputationFreeData(void *); + +IPReputationCtx *SCReputationInitCtx(); +void SCReputationFreeCtx(); + +void SCReputationPrint(Reputation *); +void SCReputationRegisterTests(void); + #endif /* __REPUTATION_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 8f6b2406ab..7c7a581850 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -88,6 +88,7 @@ #include "util-error.h" #include "detect-engine-siggroup.h" #include "util-daemon.h" +#include "reputation.h" #include "output.h" @@ -505,6 +506,7 @@ int main(int argc, char **argv) SigParsePrepare(); //PatternMatchPrepare(mpm_ctx, MPM_B2G); SCPerfInitCounterApi(); + SCReputationInitCtx(); /** \todo we need an api for these */ AppLayerDetectProtoThreadInit(); @@ -549,6 +551,7 @@ int main(int argc, char **argv) } UtInitialize(); UTHRegisterTests(); + SCReputationRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); HashTableRegisterTests(); diff --git a/src/util-error.h b/src/util-error.h index 9bf4fe61df..adbab75b5d 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -93,6 +93,9 @@ typedef enum { SC_ERR_LOGDIR_CMDLINE, SC_RADIX_TREE_GENERIC_ERROR, SC_ERR_MISSING_QUOTE, + SC_ERR_MUTEX, + SC_REPUTATION_INVALID_OPERATION, + SC_REPUTATION_INVALID_TYPE } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 8264333ec5..b884bc3bb8 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -86,7 +86,7 @@ struct in6_addr *SCRadixValidateIPV6Address(const char *addr_str) * \param stream Pointer the ip address that has to be chopped. * \param netmask The netmask value to which the ip address has to be chopped. */ -static void SCRadixChopIPAddressAgainstNetmask(uint8_t *stream, uint8_t netmask, +void SCRadixChopIPAddressAgainstNetmask(uint8_t *stream, uint8_t netmask, uint16_t key_bitlen) { int mask = 0; diff --git a/src/util-radix-tree.h b/src/util-radix-tree.h index 0f608921c8..f791760ee1 100644 --- a/src/util-radix-tree.h +++ b/src/util-radix-tree.h @@ -79,6 +79,7 @@ typedef struct SCRadixTree_ { struct in_addr *SCRadixValidateIPV4Address(const char *); struct in6_addr *SCRadixValidateIPV6Address(const char *); +void SCRadixChopIPAddressAgainstNetmask(uint8_t *, uint8_t, uint16_t); SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*)); void SCRadixReleaseRadixTree(SCRadixTree *);