static StreamMsg *StreamMsgDequeue (StreamMsgQueue *q) { SCEnter(); /* if the queue is empty there are no packets left. * In that case we sleep and try again. */ if (q->len == 0) { SCReturnPtr(NULL, "StreamMsg"); } /* pull the bottom packet from the queue */ StreamMsg *s = q->bot; /* more packets in queue */ if (q->bot->prev != NULL) { q->bot = q->bot->prev; q->bot->next = NULL; /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; } q->len--; s->next = NULL; s->prev = NULL; SCReturnPtr(s, "StreamMsg"); }
void *PoolGet(Pool *p) { SCEnter(); PoolBucket *pb = p->alloc_list; if (pb != NULL) { /* pull from the alloc list */ p->alloc_list = pb->next; p->alloc_list_size--; /* put in the empty list */ pb->next = p->empty_list; p->empty_list = pb; p->empty_list_size++; } else { if (p->max_buckets == 0 || p->allocated < p->max_buckets) { SCLogDebug("max_buckets %"PRIu32"", p->max_buckets); p->allocated++; p->outstanding++; if (p->outstanding > p->max_outstanding) p->max_outstanding = p->outstanding; SCReturnPtr(p->Alloc(p->AllocData), "void"); } else { SCReturnPtr(NULL, "void"); } } void *ptr = pb->data; pb->data = NULL; p->outstanding++; if (p->outstanding > p->max_outstanding) p->max_outstanding = p->outstanding; SCReturnPtr(ptr,"void"); }
/** * \brief Setup a pseudo packet (reassembled frags) * * Difference with PacketPseudoPktSetup is that this func doesn't increment * the recursion level. It needs to be on the same level as the frags because * we run the flow engine against this and we need to get the same flow. * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto) { SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturnPtr(NULL, "Packet"); } /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level; /* NOT incremented */ p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); p->vlan_id[0] = parent->vlan_id[0]; p->vlan_id[1] = parent->vlan_id[1]; p->vlan_idx = parent->vlan_idx; SCReturnPtr(p, "Packet"); }
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, Signature *s) { SCEnter(); DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry)); if (ste == NULL) { SCReturnPtr(NULL, "DetectThresholdEntry"); } if (PKT_IS_IPV4(p)) ste->ipv = 4; else if (PKT_IS_IPV6(p)) ste->ipv = 6; ste->sid = s->id; ste->gid = s->gid; if (td->track == TRACK_DST) { COPY_ADDRESS(&p->dst, &ste->addr); } else if (td->track == TRACK_SRC) { COPY_ADDRESS(&p->src, &ste->addr); } ste->track = td->track; ste->seconds = td->seconds; ste->tv_timeout = 0; SCReturnPtr(ste, "DetectThresholdEntry"); }
/** * \brief Setup a pseudo packet (tunnel) * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, PacketQueue *pq) { int ret; SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturnPtr(NULL, "Packet"); } /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level + 1; p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; p->tenant_id = parent->tenant_id; /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq, proto); if (unlikely(ret != TM_ECODE_OK)) { /* Not a tunnel packet, just a pseudo packet */ p->root = NULL; UNSET_TUNNEL_PKT(p); TmqhOutputPacketpool(tv, p); SCReturnPtr(NULL, "Packet"); } /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); /* disable payload (not packet) inspection on the parent, as the payload * is the packet we will now run through the system separately. We do * check it against the ip/port/other header checks though */ DecodeSetNoPayloadInspectionFlag(parent); SCReturnPtr(p, "Packet"); }
void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) { SCEnter(); if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. LocalStorageAlloc != NULL) { SCReturnPtr(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. LocalStorageAlloc(), "void *"); } SCReturnPtr(NULL, "void *"); }
/** * \brief Search for a threshold data into threshold hash table * * \param de_ctx Dectection Context * \param tsh_ptr Threshold element * \param p Packet structure * * \retval lookup_tsh Return the threshold element */ DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p) { SCEnter(); DetectThresholdEntry *lookup_tsh = NULL; SCLogDebug("tsh_ptr->track %u", tsh_ptr->track); if (tsh_ptr->track == TRACK_DST) { if (PKT_IS_IPV4(p)) { SCLogDebug("ipv4 dst"); lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst, tsh_ptr, sizeof(DetectThresholdEntry)); } else if (PKT_IS_IPV6(p)) { lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, tsh_ptr, sizeof(DetectThresholdEntry)); } } else if (tsh_ptr->track == TRACK_SRC) { if (PKT_IS_IPV4(p)) { SCLogDebug("ipv4 src"); lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src, tsh_ptr, sizeof(DetectThresholdEntry)); } else if (PKT_IS_IPV6(p)) lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, tsh_ptr, sizeof(DetectThresholdEntry)); } else { SCLogDebug("no track, weird"); } SCReturnPtr(lookup_tsh, "DetectThresholdEntry"); }
DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) { SCEnter(); DetectEngineState *s; s = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx); SCReturnPtr(s, "DetectEngineState"); }
AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) { SCEnter(); AppProto alproto = 0; int flow_proto = 0; AppLayerParserThreadCtx *tctx; tctx = SCMalloc(sizeof(*tctx)); if (tctx == NULL) goto end; memset(tctx, 0, sizeof(*tctx)); for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); tctx->alproto_local_storage[flow_proto][alproto] = AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); } } end: SCReturnPtr(tctx, "void *"); }
AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate) { SCEnter(); SCReturnPtr(pstate->decoder_events, "AppLayerDecoderEvents *"); }
void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id) { SCEnter(); void * r = NULL; r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. StateGetTx(alstate, tx_id); SCReturnPtr(r, "void *"); }
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) { SCEnter(); DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry)); if (unlikely(ste == NULL)) { SCReturnPtr(NULL, "DetectThresholdEntry"); } ste->sid = sid; ste->gid = gid; ste->track = td->track; ste->seconds = td->seconds; ste->tv_timeout = 0; SCReturnPtr(ste, "DetectThresholdEntry"); }
/** * \brief Used to lookup a SigGroupHead hash from the detection engine context * SigGroupHead hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, (void *)sgh, 0); SCReturnPtr(rsgh, "SigGroupHead"); }
/** \brief Function to allocates the Test protocol state memory */ static void *TestProtocolStateAlloc(void) { SCEnter(); void *s = SCMalloc(sizeof(TestState)); if (unlikely(s == NULL)) goto end; memset(s, 0, sizeof(TestState)); end: SCReturnPtr(s, "TestState"); }
/** * \brief Basic search improved. Limits are better handled, so * it doesn't start searches that wont fit in the remaining buffer * * \param haystack pointer to the buffer to search in * \param haystack_len length limit of the buffer * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * * \retval ptr to start of the match; NULL if no match */ uint8_t *BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint32_t needle_len) { SCEnter(); const uint8_t *h, *n; const uint8_t *hmax = haystack + haystack_len; const uint8_t *nmax = needle + needle_len; if (needle_len == 0 || needle_len > haystack_len) { SCReturnPtr(NULL, "uint8_t"); } //PrintRawDataFp(stdout,needle,needle_len); //PrintRawDataFp(stdout,haystack,haystack_len); for (n = needle; nmax - n <= hmax - haystack; haystack++) { if (*haystack != *n) { continue; } SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); /* one byte needles */ if (needle_len == 1) { SCReturnPtr((uint8_t *)haystack, "uint8_t"); } for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { if (*h != *n) { break; } SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); /* if we run out of needle we fully matched */ if (n == nmax - 1) { SCReturnPtr((uint8_t *)haystack, "uint8_t"); } } n = needle; } SCReturnPtr(NULL, "uint8_t"); }
AppLayerParserState *AppLayerParserStateAlloc(void) { SCEnter(); AppLayerParserState *pstate = (AppLayerParserState *)SCMalloc(sizeof(*pstate)); if (pstate == NULL) goto end; memset(pstate, 0, sizeof(*pstate)); end: SCReturnPtr(pstate, "AppLayerParserState"); }
/** \brief Create a new http log LogFilestoreCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful * */ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("Could not create new LogFilestoreCtx"); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = NULL; output_ctx->DeInit = LogFilestoreLogDeInitCtx; char *s_default_log_dir = NULL; s_default_log_dir = ConfigGetLogDirectory(); const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { strlcpy(g_logfile_base_dir, s_default_log_dir, sizeof(g_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { strlcpy(g_logfile_base_dir, s_base_dir, sizeof(g_logfile_base_dir)); } else { snprintf(g_logfile_base_dir, sizeof(g_logfile_base_dir), "%s/%s", s_default_log_dir, s_base_dir); } } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for stored files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); SCLogInfo("forcing md5 calculation for stored files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif } SCLogInfo("storing files in %s", g_logfile_base_dir); SCReturnPtr(output_ctx, "OutputCtx"); }
/** * \brief Setup a pseudo packet (tunnel) * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto) { SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnPtr(NULL, "Packet"); } /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level + 1; p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; /* set tunnel flags */ /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); /* disable payload (not packet) inspection on the parent, as the payload * is the packet we will now run through the system separately. We do * check it against the ip/port/other header checks though */ DecodeSetNoPayloadInspectionFlag(parent); SCReturnPtr(p, "Packet"); }
FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction) { SCEnter(); FileContainer *ptr = NULL; if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. StateGetFiles != NULL) { ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. StateGetFiles(alstate, direction); } SCReturnPtr(ptr, "FileContainer *"); }
AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id) { SCEnter(); AppLayerDecoderEvents *ptr = NULL; if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. StateGetEvents != NULL) { ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. StateGetEvents(alstate, tx_id); } SCReturnPtr(ptr, "AppLayerDecoderEvents *"); }
/** * \brief Find the magic value for a buffer. * * \param buf the buffer * \param buflen length of the buffer * * \retval result pointer to null terminated string */ char *MagicThreadLookup(magic_t *ctx, uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; if (buf != NULL && buflen > 0) { result = magic_buffer(*ctx, (void *)buf, (size_t)buflen); if (result != NULL) { magic = SCStrdup(result); if (unlikely(magic == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic"); } } } SCReturnPtr(magic, "const char"); }
/** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("Could not create new LogFileCtx"); return NULL; } if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = logfile_ctx; output_ctx->DeInit = LogFileLogDeInitCtx; const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { FileForceFilestoreEnable(); SCLogInfo("forcing filestore of all files"); } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for logged files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); SCLogInfo("forcing md5 calculation for logged files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif } FileForceTrackingEnable(); SCReturnPtr(output_ctx, "OutputCtx"); }
/** * \brief Find the magic value for a buffer. * * \param buf the buffer * \param buflen length of the buffer * * \retval result pointer to null terminated string */ char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; SCMutexLock(&g_magic_lock); if (buf != NULL && buflen > 0) { result = magic_buffer(g_magic_ctx, (void *)buf, (size_t)buflen); if (result != NULL) { magic = SCStrdup(result); if (unlikely(magic == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic"); } } } SCMutexUnlock(&g_magic_lock); SCReturnPtr(magic, "const char"); }
AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) { SCEnter(); AppProto i = 0; int j = 0; AppLayerParserThreadCtx *tctx; tctx = SCMalloc(sizeof(*tctx)); if (tctx == NULL) goto end; memset(tctx, 0, sizeof(*tctx)); for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { for (j = 0; j < ALPROTO_MAX; j++) { tctx->alproto_local_storage[i][j] = AppLayerParserGetProtocolParserLocalStorage(FlowGetReverseProtoMapping(i), j); } } end: SCReturnPtr(tctx, "void *"); }
static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *f, struct DnsQueryGetDataArgs *cbdata, int list_id, bool first) { SCEnter(); InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); if (buffer == NULL) return NULL; if (!first && buffer->inspect != NULL) return buffer; const uint8_t *data; uint32_t data_len; if (rs_dns_tx_get_query_name(cbdata->txv, (uint16_t)cbdata->local_id, (uint8_t **)&data, &data_len) == 0) { return NULL; } InspectionBufferSetup(buffer, data, data_len); InspectionBufferApplyTransforms(buffer, transforms); SCReturnPtr(buffer, "InspectionBuffer"); }
/** \internal * * \brief This function is used to parse Modbus parameters in function mode * * \param str Pointer to the user provided id option * * \retval id_d pointer to DetectModbusData on success * \retval NULL on failure */ static DetectModbus *DetectModbusFunctionParse(char *str) { SCEnter(); DetectModbus *modbus = NULL; char arg[MAX_SUBSTRINGS], *ptr = arg; int ov[MAX_SUBSTRINGS], res, ret; ret = pcre_exec(function_parse_regex, function_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) goto error; res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct Modbus function option */ modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); if (unlikely(modbus == NULL)) goto error; if (isdigit(ptr[0])) { modbus->function = atoi((const char*) ptr); SCLogDebug("will look for modbus function %d", modbus->function); if (ret > 2) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 3, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct address option */ modbus->subfunction =(uint16_t *) SCCalloc(1, sizeof(uint16_t)); if (modbus->subfunction == NULL) goto error; *(modbus->subfunction) = atoi((const char*) arg); SCLogDebug("and subfunction %d", *(modbus->subfunction)); } } else { uint8_t neg = 0; if (ptr[0] == '!') { neg = 1; ptr++; } if (strcmp("assigned", ptr) == 0) modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED; else if (strcmp("unassigned", ptr) == 0) modbus->category = MODBUS_CAT_PUBLIC_UNASSIGNED; else if (strcmp("public", ptr) == 0) modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED | MODBUS_CAT_PUBLIC_UNASSIGNED; else if (strcmp("user", ptr) == 0) modbus->category = MODBUS_CAT_USER_DEFINED; else if (strcmp("reserved", ptr) == 0) modbus->category = MODBUS_CAT_RESERVED; else if (strcmp("all", ptr) == 0) modbus->category = MODBUS_CAT_ALL; if (neg) modbus->category = ~modbus->category; SCLogDebug("will look for modbus category function %d", modbus->category); } SCReturnPtr(modbus, "DetectModbusFunction"); error: if (modbus != NULL) DetectModbusFree(modbus); SCReturnPtr(NULL, "DetectModbus"); }
/** \internal * * \brief This function is used to parse Modbus parameters in access mode * * \param str Pointer to the user provided id option * * \retval Pointer to DetectModbusData on success or NULL on failure */ static DetectModbus *DetectModbusAccessParse(char *str) { SCEnter(); DetectModbus *modbus = NULL; char arg[MAX_SUBSTRINGS]; int ov[MAX_SUBSTRINGS], ret, res; ret = pcre_exec(access_parse_regex, access_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) goto error; res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct Modbus option */ modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); if (unlikely(modbus == NULL)) goto error; if (strcmp(arg, "read") == 0) modbus->type = MODBUS_TYP_READ; else if (strcmp(arg, "write") == 0) modbus->type = MODBUS_TYP_WRITE; else goto error; if (ret > 2) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 2, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (*arg != '\0') { if (strcmp(arg, "discretes") == 0) { if (modbus->type == MODBUS_TYP_WRITE) /* Discrete access is only read access. */ goto error; modbus->type |= MODBUS_TYP_DISCRETES; } else if (strcmp(arg, "coils") == 0) { modbus->type |= MODBUS_TYP_COILS; } else if (strcmp(arg, "input") == 0) { if (modbus->type == MODBUS_TYP_WRITE) { /* Input access is only read access. */ goto error; } modbus->type |= MODBUS_TYP_INPUT; } else if (strcmp(arg, "holding") == 0) { modbus->type |= MODBUS_TYP_HOLDING; } else goto error; } if (ret > 4) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 4, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct address option */ modbus->address = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); if (unlikely(modbus->address == NULL)) goto error; if (arg[0] == '>') { modbus->address->min = atoi((const char*) (arg+1)); modbus->address->mode = DETECT_MODBUS_GT; } else if (arg[0] == '<') { modbus->address->min = atoi((const char*) (arg+1)); modbus->address->mode = DETECT_MODBUS_LT; } else { modbus->address->min = atoi((const char*) arg); } SCLogDebug("and min/equal address %d", modbus->address->min); if (ret > 5) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 5, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (*arg != '\0') { modbus->address->max = atoi((const char*) (arg+2)); modbus->address->mode = DETECT_MODBUS_RA; SCLogDebug("and max address %d", modbus->address->max); } if (ret > 7) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 7, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (modbus->address->mode != DETECT_MODBUS_EQ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords (address range and value)."); goto error; } /* We have a correct address option */ modbus->data = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); if (unlikely(modbus->data == NULL)) goto error; if (arg[0] == '>') { modbus->data->min = atoi((const char*) (arg+1)); modbus->data->mode = DETECT_MODBUS_GT; } else if (arg[0] == '<') { modbus->data->min = atoi((const char*) (arg+1)); modbus->data->mode = DETECT_MODBUS_LT; } else { modbus->data->min = atoi((const char*) arg); } SCLogDebug("and min/equal value %d", modbus->data->min); if (ret > 8) { res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 8, arg, MAX_SUBSTRINGS); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (*arg != '\0') { modbus->data->max = atoi((const char*) (arg+2)); modbus->data->mode = DETECT_MODBUS_RA; SCLogDebug("and max value %d", modbus->data->max); } } } } } } SCReturnPtr(modbus, "DetectModbusAccess"); error: if (modbus != NULL) DetectModbusFree(modbus); SCReturnPtr(NULL, "DetectModbus"); }
static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, File *curr_file, uint8_t flags, uint32_t *buffer_len, uint32_t *stream_start_offset) { SCEnter(); int index = 0; const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; uint64_t file_size = FileDataSize(curr_file); if (det_ctx->smtp_buffers_list_len == 0) { if (SMTPCreateSpace(det_ctx, 1) < 0) goto end; index = 0; if (det_ctx->smtp_buffers_list_len == 0) { det_ctx->smtp_start_tx_id = tx_id; } det_ctx->smtp_buffers_list_len++; } else { if ((tx_id - det_ctx->smtp_start_tx_id) < det_ctx->smtp_buffers_list_len) { if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len; *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset; buffer = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; SCReturnPtr(buffer, "uint8_t"); } } else { if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0) goto end; if (det_ctx->smtp_buffers_list_len == 0) { det_ctx->smtp_start_tx_id = tx_id; } det_ctx->smtp_buffers_list_len++; } index = (tx_id - det_ctx->smtp_start_tx_id); } SCLogDebug("smtp_config.content_limit %u, smtp_config.content_inspect_min_size %u", smtp_config.content_limit, smtp_config.content_inspect_min_size); SCLogDebug("file %p size %"PRIu64", state %d", curr_file, file_size, curr_file->state); /* no new data */ if (curr_file->content_inspected == file_size) { SCLogDebug("no new data"); goto end; } if (file_size == 0) { SCLogDebug("no data to inspect for this transaction"); goto end; } if ((smtp_config.content_limit == 0 || file_size < smtp_config.content_limit) && file_size < smtp_config.content_inspect_min_size && !(flags & STREAM_EOF) && !(curr_file->state > FILE_STATE_OPENED)) { SCLogDebug("we still haven't seen the entire content. " "Let's defer content inspection till we see the " "entire content."); goto end; } StreamingBufferGetDataAtOffset(curr_file->sb, &det_ctx->smtp[index].buffer, &det_ctx->smtp[index].buffer_len, curr_file->content_inspected); det_ctx->smtp[index].offset = curr_file->content_inspected; /* updat inspected tracker */ curr_file->content_inspected = FileDataSize(curr_file); SCLogDebug("content_inspected %"PRIu64", offset %"PRIu64, curr_file->content_inspected, det_ctx->smtp[index].offset); buffer = det_ctx->smtp[index].buffer; *buffer_len = det_ctx->smtp[index].buffer_len; *stream_start_offset = det_ctx->smtp[index].offset; end: SCLogDebug("buffer %p, len %u", buffer, *buffer_len); SCReturnPtr(buffer, "uint8_t"); }
/** * \internal * \brief This function is used to parse reference options passed via reference: keyword * * \param rawstr Pointer to the user provided reference options. * * \retval ref Pointer to signature reference on success. * \retval NULL On failure. */ static DetectReference *DetectReferenceParse(char *rawstr, DetectEngineCtx *de_ctx) { SCEnter(); DetectReference *ref = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *key = NULL; const char *content = NULL; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unable to parse \"reference\" " "keyword argument - \"%s\". Invalid argument.", rawstr); goto error; } ref = SCMalloc(sizeof(DetectReference)); if (unlikely(ref == NULL)) { goto error; } memset(ref, 0, sizeof(DetectReference)); res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &key); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &content); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (key == NULL || content == NULL) goto error; SCRConfReference *lookup_ref_conf = SCRConfGetReference(key, de_ctx); if (lookup_ref_conf != NULL) { ref->key = lookup_ref_conf->url; } else { SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". " "Supported keys are defined in reference.config file. Please " "have a look at the conf param \"reference-config-file\"", key); goto error; } /* make a copy so we can free pcre's substring */ ref->reference = SCStrdup((char *)content); if (ref->reference == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno)); goto error; } /* free the substrings */ pcre_free_substring(key); pcre_free_substring(content); SCReturnPtr(ref, "Reference"); error: if (key != NULL) pcre_free_substring(key); if (content != NULL) pcre_free_substring(content); if (ref != NULL) DetectReferenceFree(ref); SCReturnPtr(NULL, "Reference"); }
/** * \internal * \brief This function is used to parse flags options passed via flags: keyword * * \param rawstr Pointer to the user provided flags options * * \retval de pointer to DetectFlagsData on success * \retval NULL on failure */ static DetectFlagsData *DetectFlagsParse (const char *rawstr) { SCEnter(); #define MAX_SUBSTRINGS 30 int ret = 0, found = 0, ignore = 0, res = 0; int ov[MAX_SUBSTRINGS]; char *ptr; char arg1[16] = ""; char arg2[16] = ""; char arg3[16] = ""; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); SCLogDebug("input '%s', pcre said %d", rawstr, ret); if (ret < 3) { SCLogError(SC_ERR_PCRE_MATCH, "pcre match failed"); SCReturnPtr(NULL, "DetectFlagsData"); } res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCReturnPtr(NULL, "DetectFlagsData"); } if (ret >= 2) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCReturnPtr(NULL, "DetectFlagsData"); } } if (ret >= 3) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCReturnPtr(NULL, "DetectFlagsData"); } } SCLogDebug("args '%s', '%s', '%s'", arg1, arg2, arg3); if (strlen(arg2) == 0) { SCLogDebug("empty argument"); SCReturnPtr(NULL, "DetectFlagsData"); } DetectFlagsData *de = SCMalloc(sizeof(DetectFlagsData)); if (unlikely(de == NULL)) goto error; memset(de, 0, sizeof(DetectFlagsData)); de->ignored_flags = 0xff; /** First parse args1 */ ptr = arg1; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->flags |= TH_SYN; found++; break; case 'A': case 'a': de->flags |= TH_ACK; found++; break; case 'F': case 'f': de->flags |= TH_FIN; found++; break; case 'R': case 'r': de->flags |= TH_RST; found++; break; case 'P': case 'p': de->flags |= TH_PUSH; found++; break; case 'U': case 'u': de->flags |= TH_URG; found++; break; case '1': de->flags |= TH_CWR; found++; break; case '2': de->flags |= TH_ECN; found++; break; case 'C': case 'c': de->flags |= TH_CWR; found++; break; case 'E': case 'e': de->flags |= TH_ECN; found++; break; case '0': de->flags = 0; found++; break; case '!': de->modifier = MODIFIER_NOT; break; case '+': de->modifier = MODIFIER_PLUS; break; case '*': de->modifier = MODIFIER_ANY; break; } ptr++; } /** Second parse first set of flags */ if (strlen(arg2) > 0) { ptr = arg2; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->flags |= TH_SYN; found++; break; case 'A': case 'a': de->flags |= TH_ACK; found++; break; case 'F': case 'f': de->flags |= TH_FIN; found++; break; case 'R': case 'r': de->flags |= TH_RST; found++; break; case 'P': case 'p': de->flags |= TH_PUSH; found++; break; case 'U': case 'u': de->flags |= TH_URG; found++; break; case '1': case 'C': case 'c': de->flags |= TH_CWR; found++; break; case '2': case 'E': case 'e': de->flags |= TH_ECN; found++; break; case '0': de->flags = 0; found++; break; case '!': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_NOT; SCLogDebug("NOT modifier is set"); break; case '+': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_PLUS; SCLogDebug("PLUS modifier is set"); break; case '*': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_ANY; SCLogDebug("ANY modifier is set"); break; default: break; } ptr++; } if (found == 0) goto error; } /** Finally parse ignored flags */ if (strlen(arg3) > 0) { ptr = arg3; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->ignored_flags &= ~TH_SYN; ignore++; break; case 'A': case 'a': de->ignored_flags &= ~TH_ACK; ignore++; break; case 'F': case 'f': de->ignored_flags &= ~TH_FIN; ignore++; break; case 'R': case 'r': de->ignored_flags &= ~TH_RST; ignore++; break; case 'P': case 'p': de->ignored_flags &= ~TH_PUSH; ignore++; break; case 'U': case 'u': de->ignored_flags &= ~TH_URG; ignore++; break; case '1': de->ignored_flags &= ~TH_CWR; ignore++; break; case '2': de->ignored_flags &= ~TH_ECN; ignore++; break; case 'C': case 'c': de->ignored_flags &= ~TH_CWR; ignore++; break; case 'E': case 'e': de->ignored_flags &= ~TH_ECN; ignore++; break; case '0': break; default: break; } ptr++; } if (ignore == 0) { SCLogDebug("ignore == 0"); goto error; } } SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore); SCReturnPtr(de, "DetectFlagsData"); error: if (de) { SCFree(de); } SCReturnPtr(NULL, "DetectFlagsData"); }