/** * Function doing a lookup in expectation list and updating Flow if needed. * * This function lookup for a existing expectation that could match the Flow. * If found and if the expectation contains data it store the data in the * expectation storage of the Flow. * * \return an AppProto value if found * \return ALPROTO_UNKNOWN if not found */ AppProto AppLayerExpectationHandle(Flow *f, int direction) { AppProto alproto = ALPROTO_UNKNOWN; IPPair *ipp = NULL; Expectation *lexp = NULL; Expectation *pexp = NULL; int x = SC_ATOMIC_GET(expectation_count); if (x == 0) { return ALPROTO_UNKNOWN; } /* Call will take reference of the ip pair in 'ipp' */ Expectation *exp = AppLayerExpectationLookup(f, direction, &ipp); if (exp == NULL) goto out; time_t ctime = f->lastts.tv_sec; pexp = NULL; while (exp) { lexp = exp->next; if ( (exp->direction & direction) && ((exp->sp == 0) || (exp->sp == f->sp)) && ((exp->dp == 0) || (exp->dp == f->dp))) { alproto = exp->alproto; f->alproto_ts = alproto; f->alproto_tc = alproto; void *fdata = FlowGetStorageById(f, g_expectation_id); if (fdata) { /* We already have an expectation so let's clean this one */ ExpectationDataFree(exp->data); } else { /* Transfer ownership of Expectation data to the Flow */ if (FlowSetStorageById(f, g_expectation_data_id, exp->data) != 0) { SCLogDebug("Unable to set flow storage"); } } exp->data = NULL; exp = RemoveExpectationAndGetNext(ipp, pexp, exp, lexp); continue; } /* Cleaning remove old entries */ if (exp && (ctime > exp->ts.tv_sec + EXPECTATION_TIMEOUT)) { exp = RemoveExpectationAndGetNext(ipp, pexp, exp, lexp); continue; } pexp = exp; exp = lexp; } out: if (ipp) IPPairRelease(ipp); return alproto; }
static int FlowStorageTest02(void) { Flow *f = NULL; StorageInit(); int id1 = FlowStorageRegister("test", sizeof(void *), NULL, StorageTestFree); if (id1 < 0) goto error; if (StorageFinalize() < 0) goto error; FlowInitConfig(FLOW_QUIET); f = FlowAlloc(); if (f == NULL) { goto error; } void *ptr = FlowGetStorageById(f, id1); if (ptr != NULL) { goto error; } void *ptr1a = SCMalloc(128); if (ptr1a == NULL) { goto error; } FlowSetStorageById(f, id1, ptr1a); void *ptr1b = FlowGetStorageById(f, id1); if (ptr1a != ptr1b) { goto error; } FlowClearMemory(f, 0); FlowFree(f); FlowShutdown(); StorageCleanup(); return 1; error: if (f != NULL) { FlowClearMemory(f, 0); FlowFree(f); } FlowShutdown(); StorageCleanup(); return 0; }
/** * \brief This function is used to add a tag to a session (type session) * or update it if it's already installed. The number of times to * allow an update is limited by DETECT_TAG_MATCH_LIMIT. This way * repetitive matches to the same rule are limited of setting tags, * to avoid DOS attacks * * \param p pointer to the current packet * \param tde pointer to the new DetectTagDataEntry * * \retval 0 if the tde was added succesfuly * \retval 1 if an entry of this sid/gid already exist and was updated */ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) { uint8_t updated = 0; uint16_t num_tags = 0; DetectTagDataEntry *iter = NULL; if (p->flow == NULL) return 1; FLOWLOCK_WRLOCK(p->flow); iter = FlowGetStorageById(p->flow, flow_tag_id); if (iter != NULL) { /* First iterate installed entries searching a duplicated sid/gid */ for (; iter != NULL; iter = iter->next) { num_tags++; if (iter->sid == tde->sid && iter->gid == tde->gid) { iter->cnt_match++; /* If so, update data, unless the maximum MATCH limit is * reached. This prevents possible DOS attacks */ if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) { /* Reset time and counters */ iter->first_ts = iter->last_ts = tde->first_ts; iter->packets = 0; iter->bytes = 0; } updated = 1; break; } } } /* If there was no entry of this rule, prepend the new tde */ if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) { DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { new_tde->next = FlowGetStorageById(p->flow, flow_tag_id); FlowSetStorageById(p->flow, flow_tag_id, new_tde); (void) SC_ATOMIC_ADD(num_tags, 1); } } else if (num_tags == DETECT_TAG_MAX_TAGS) { SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags); } FLOWLOCK_UNLOCK(p->flow); return updated; }
static void TagHandlePacketFlow(Flow *f, Packet *p) { if (FlowGetStorageById(f, flow_tag_id) == NULL) return; DetectTagDataEntry *tde = NULL; DetectTagDataEntry *prev = NULL; DetectTagDataEntry *iter = FlowGetStorageById(f, flow_tag_id); uint8_t flag_added = 0; while (iter != NULL) { /* update counters */ iter->last_ts = p->ts.tv_sec; switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: iter->packets++; break; case DETECT_TAG_METRIC_BYTES: iter->bytes += GET_PKT_LEN(p); break; } /* If this packet triggered the rule with tag, we dont need * to log it (the alert will log it) */ if (!(iter->flags & TAG_ENTRY_FLAG_SKIPPED_FIRST)) { iter->flags |= TAG_ENTRY_FLAG_SKIPPED_FIRST; } else { /* Update metrics; remove if tag expired; and set alerts */ switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: if (iter->packets > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_BYTES: if (iter->bytes > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_SECONDS: /* last_ts handles this metric, but also a generic time based * expiration to prevent dead sessions/hosts */ if (iter->last_ts - iter->first_ts > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; } } prev = iter; iter = iter->next; } }