/** * \brief this funciton prints an error message and exits. * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with PfringThreadVars */ TmEcode NoPfringSupportExit(ThreadVars *tv, const void *initdata, void **data) { SCLogError(SC_ERR_NO_PF_RING,"Error creating thread %s: you do not have support for pfring " "enabled please recompile with --enable-pfring", tv->name); exit(EXIT_FAILURE); }
DetectUrilenData *DetectUrilenParse (char *urilenstr) { DetectUrilenData *urilend = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; char *arg4 = NULL; char *arg5 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, urilenstr, strlen(urilenstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 6) { SCLogError(SC_ERR_PCRE_PARSE, "urilen option pcre parse error: \"%s\"", urilenstr); goto error; } const char *str_ptr; SCLogDebug("ret %d", ret); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret > 3) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); if (ret > 4) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg4 = (char *) str_ptr; SCLogDebug("Arg4 \"%s\"", arg4); } if (ret > 5) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 5, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg5 = (char *) str_ptr; SCLogDebug("Arg5 \"%s\"", arg5); } } urilend = SCMalloc(sizeof (DetectUrilenData)); if (unlikely(urilend == NULL)) goto error; memset(urilend, 0, sizeof(DetectUrilenData)); if (arg1[0] == '<') urilend->mode = DETECT_URILEN_LT; else if (arg1[0] == '>') urilend->mode = DETECT_URILEN_GT; else urilend->mode = DETECT_URILEN_EQ; if (arg3 != NULL && strcmp("<>", arg3) == 0) { if (strlen(arg1) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } urilend->mode = DETECT_URILEN_RA; } /** set the first urilen value */ if (ByteExtractStringUint16(&urilend->urilen1,10,strlen(arg2),arg2) <= 0){ SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg2); goto error; } /** set the second urilen value if specified */ if (arg4 != NULL && strlen(arg4) > 0) { if (urilend->mode != DETECT_URILEN_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple urilen values specified" " but mode is not range"); goto error; } if(ByteExtractStringUint16(&urilend->urilen2,10,strlen(arg4),arg4) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg4); goto error; } if (urilend->urilen2 <= urilend->urilen1){ SCLogError(SC_ERR_INVALID_ARGUMENT,"urilen2:%"PRIu16" <= urilen:" "%"PRIu16"",urilend->urilen2,urilend->urilen1); goto error; } } if (arg5 != NULL) { if (strcasecmp("raw", arg5) == 0) { urilend->raw_buffer = 1; } } pcre_free_substring(arg1); pcre_free_substring(arg2); if (arg3 != NULL) pcre_free_substring(arg3); if (arg4 != NULL) pcre_free_substring(arg4); if (arg5 != NULL) pcre_free_substring(arg5); return urilend; error: if (urilend) SCFree(urilend); if (arg1 != NULL) SCFree(arg1); if (arg2 != NULL) SCFree(arg2); if (arg3 != NULL) SCFree(arg3); if (arg4 != NULL) SCFree(arg4); return NULL; }
/** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectIdData on success * \retval NULL on failure */ DetectIdData *DetectIdParse (char *idstr) { uint32_t temp; DetectIdData *id_d = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, idstr, strlen(idstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid id option. The id option value must be" " in the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); goto error; } if (ret > 1) { const char *str_ptr; char *orig; char *tmp_str; res = pcre_get_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ id_d = SCMalloc(sizeof(DetectIdData)); if (id_d == NULL) goto error; orig = SCStrdup((char*)str_ptr); tmp_str=orig; if (tmp_str == NULL) { goto error; } /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } /* ok, fill the id data */ temp = atoi((char *)tmp_str); if (temp > DETECT_IPID_MAX) { SCLogError(SC_ERR_INVALID_VALUE, "\"id\" option must be in " "the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); SCFree(orig); goto error; } id_d->id = temp; SCFree(orig); SCLogDebug("detect-id: will look for ip_id: %u\n", id_d->id); } return id_d; error: if (id_d != NULL) DetectIdFree(id_d); return NULL; }
/** * \retval 2 silent match (no alert but apply actions) * \retval 1 normal match * \retval 0 no match */ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) { int ret = 0; DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid); SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid); switch(td->type) { case TYPE_LIMIT: { SCLogDebug("limit"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count <= td->count) { ret = 1; } else { ret = 2; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; ret = 1; } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->tv_sec1 = p->ts.tv_sec; e->current_count = 1; ret = 1; e->next = HostGetStorageById(h, threshold_id); HostSetStorageById(h, threshold_id, e); } break; } case TYPE_THRESHOLD: { SCLogDebug("threshold"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { ret = 1; lookup_tsh->current_count = 0; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; } } else { if (td->count == 1) { ret = 1; } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->next = HostGetStorageById(h, threshold_id); HostSetStorageById(h, threshold_id, e); } } break; } case TYPE_BOTH: { SCLogDebug("both"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { /* within time limit */ lookup_tsh->current_count++; if (lookup_tsh->current_count == td->count) { ret = 1; } else if (lookup_tsh->current_count > td->count) { /* silent match */ ret = 2; } } else { /* expired, so reset */ lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; /* if we have a limit of 1, this is a match */ if (lookup_tsh->current_count == td->count) { ret = 1; } } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->next = HostGetStorageById(h, threshold_id); HostSetStorageById(h, threshold_id, e); /* for the first match we return 1 to * indicate we should alert */ if (td->count == 1) { ret = 1; } } break; } /* detection_filter */ case TYPE_DETECTION: { SCLogDebug("detection_filter"); if (lookup_tsh != NULL) { long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) - (lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0)); if (time_diff < td->seconds) { /* within timeout */ lookup_tsh->current_count++; if (lookup_tsh->current_count > td->count) { ret = 1; } } else { /* expired, reset */ lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->tv_usec1 = p->ts.tv_usec; lookup_tsh->current_count = 1; } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_usec1 = p->ts.tv_usec; e->next = HostGetStorageById(h, threshold_id); HostSetStorageById(h, threshold_id, e); } break; } /* rate_filter */ case TYPE_RATE: { SCLogDebug("rate_filter"); ret = 1; if (lookup_tsh != NULL) { /* Check if we have a timeout enabled, if so, * we still matching (and enabling the new_action) */ if (lookup_tsh->tv_timeout != 0) { if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ lookup_tsh->tv_timeout = 0; } else { /* Already matching */ /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: PACKET_ALERT(p); break; case TH_ACTION_DROP: PACKET_DROP(p); break; case TH_ACTION_REJECT: PACKET_REJECT(p); break; case TH_ACTION_PASS: PACKET_PASS(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */ } else { /* Update the matching state with the timeout interval */ if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count > td->count) { /* Then we must enable the new action by setting a * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: PACKET_ALERT(p); break; case TH_ACTION_DROP: PACKET_DROP(p); break; case TH_ACTION_REJECT: PACKET_REJECT(p); break; case TH_ACTION_PASS: PACKET_PASS(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; } } /* else - if (lookup_tsh->tv_timeout != 0) */ } else { if (td->count == 1) { ret = 1; } DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_timeout = 0; e->next = HostGetStorageById(h, threshold_id); HostSetStorageById(h, threshold_id, e); } break; } case TYPE_SUPPRESS: { int res = 0; switch (td->track) { case TRACK_DST: res = DetectAddressMatch(td->addr, &p->dst); break; case TRACK_SRC: res = DetectAddressMatch(td->addr, &p->src); break; case TRACK_RULE: default: SCLogError(SC_ERR_INVALID_VALUE, "track mode %d is not supported", td->track); break; } if (res == 0) ret = 1; else ret = 2; /* suppressed but still need actions */ break; } default: SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); } return ret; }
int NetmapRunModeIsIPS() { int nlive = LiveGetDeviceCount(); int ldev; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *netmap_node; int has_ips = 0; int has_ids = 0; /* Find initial node */ netmap_node = ConfGetNode("netmap"); if (netmap_node == NULL) { return 0; } if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); for (ldev = 0; ldev < nlive; ldev++) { const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; } char *copymodestr = NULL; if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); if (if_root == NULL) { if (if_default == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; } if_root = if_default; } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (strcmp(copymodestr, "ips") == 0) { has_ips = 1; } else { has_ids = 1; } } else { has_ids = 1; } } if (has_ids && has_ips) { SCLogInfo("Netmap mode using IPS and IDS mode"); for (ldev = 0; ldev < nlive; ldev++) { const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; } if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); char *copymodestr = NULL; if (if_root == NULL) { if (if_default == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; } if_root = if_default; } if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) && (strcmp(copymodestr, "ips") == 0))) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Netmap IPS mode used and interface '%s' is in IDS or TAP mode. " "Sniffing '%s' but expect bad result as stream-inline is activated.", live_dev, live_dev); } } } return has_ips; }
/** * \brief This function is used to parse ssl_version data passed via * keyword: "ssl_version" * * \param str Pointer to the user provided options * * \retval ssl pointer to DetectSslVersionData on success * \retval NULL on failure */ DetectSslVersionData *DetectSslVersionParse(char *str) { DetectSslVersionData *ssl = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 5) { SCLogError(SC_ERR_PCRE_MATCH, "invalid ssl_version option"); goto error; } if (ret > 1) { const char *str_ptr[5]; char *orig; uint8_t found = 0, neg = 0; char *tmp_str; /* We have a correct ssl_version options */ ssl = SCCalloc(1, sizeof (DetectSslVersionData)); if (unlikely(ssl == NULL)) goto error; int i; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); if (found == 0) goto error; break; } orig = SCStrdup((char*) str_ptr[i]); if (unlikely(orig == NULL)) { goto error; } tmp_str = orig; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } if (tmp_str[0] == '!') { neg = 1; tmp_str++; } if (strncasecmp("sslv2", tmp_str, 5) == 0) { ssl->data[SSLv2].ver = SSL_VERSION_2; if (neg == 1) ssl->data[SSLv2].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("sslv3", tmp_str, 5) == 0) { ssl->data[SSLv3].ver = SSL_VERSION_3; if (neg == 1) ssl->data[SSLv3].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.0", tmp_str, 6) == 0) { ssl->data[TLS10].ver = TLS_VERSION_10; if (neg == 1) ssl->data[TLS10].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.1", tmp_str, 6) == 0) { ssl->data[TLS11].ver = TLS_VERSION_11; if (neg == 1) ssl->data[TLS11].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.2", tmp_str, 6) == 0) { ssl->data[TLS12].ver = TLS_VERSION_12; if (neg == 1) ssl->data[TLS12].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strcmp(tmp_str, "") == 0) { SCFree(orig); if (found == 0) goto error; break; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); SCFree(orig); goto error; } found = 1; neg = 0; SCFree(orig); } } return ssl; error: if (ssl != NULL) DetectSslVersionFree(ssl); return NULL; }
/** * \brief Main PCAP file reading Loop function */ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); int packet_q_len = 64; PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; int r; TmSlot *s = (TmSlot *)slot; ptv->slot = s->slot_next; ptv->cb_result = TM_ECODE_OK; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ PacketPoolWait(); /* Right now we just support reading packets one at a time. */ r = pcap_dispatch(pcap_g.pcap_handle, packet_q_len, (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv); if (unlikely(r == -1)) { SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(pcap_g.pcap_handle)); if (! RunModeUnixSocketIsActive()) { /* in the error state we just kill the engine */ EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } else if (unlikely(r == 0)) { SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r); if (! RunModeUnixSocketIsActive()) { EngineStop(); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } break; } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed"); if (! RunModeUnixSocketIsActive()) { EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); }
/** * \brief Parses a line from the classification file and adds it to Classtype * hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht. * * \param rawstr Pointer to the string to be parsed. * \param index Relative index of the string to be parsed. * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx) { const char *ct_name = NULL; const char *ct_desc = NULL; const char *ct_priority_str = NULL; int ct_priority = 0; uint8_t ct_id = index; SCClassConfClasstype *ct_new = NULL; SCClassConfClasstype *ct_lookup = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid Classtype in " "classification.config file"); goto error; } /* retrieve the classtype name */ ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } /* retrieve the classtype description */ ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } /* retrieve the classtype priority */ ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } if (ct_priority_str == NULL) { goto error; } ct_priority = atoi(ct_priority_str); /* Create a new instance of the parsed Classtype string */ ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority); if (ct_new == NULL) goto error; /* Check if the Classtype is present in the HashTable. In case it's present * ignore it, as it is a duplicate. If not present, add it to the table */ ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0); if (ct_lookup == NULL) { if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0) SCLogDebug("HashTable Add failed"); } else { SCLogDebug("Duplicate classtype found inside classification.config"); if (ct_new->classtype_desc) SCFree(ct_new->classtype_desc); if (ct_new->classtype) SCFree(ct_new->classtype); SCFree(ct_new); } if (ct_name) SCFree((char *)ct_name); if (ct_desc) SCFree((char *)ct_desc); if (ct_priority_str) SCFree((char *)ct_priority_str); return 0; error: if (ct_name) SCFree((char *)ct_name); if (ct_desc) SCFree((char *)ct_desc); if (ct_priority_str) SCFree((char *)ct_priority_str); return -1; }
/** * \brief Inits the context to be used by the Classification Config parsing API. * * This function initializes the hash table to be used by the Detection * Engine Context to hold the data from the classification.config file, * obtains the file desc to parse the classification.config file, and * inits the regex used to parse the lines from classification.config * file. * * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) { char *filename = NULL; const char *eb = NULL; int eo; int opts = 0; /* init the hash table to be used by the classification config Classtypes */ de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc, SCClassConfClasstypeHashCompareFunc, SCClassConfClasstypeHashFree); if (de_ctx->class_conf_ht == NULL) { SCLogError(SC_ERR_HASH_TABLE_INIT, "Error initializing the hash " "table"); goto error; } /* if it is not NULL, use the file descriptor. The hack so that we can * avoid using a dummy classification file for testing purposes and * instead use an input stream against a buffer containing the * classification strings */ if (fd == NULL) { filename = SCClassConfGetConfFilename(); if ( (fd = fopen(filename, "r")) == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); if (regex == NULL) { SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_CLASSCONFIG_REGEX, eo, eb); goto error; } regex_study = pcre_study(regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return 0; error: if (de_ctx->class_conf_ht != NULL) { HashTableFree(de_ctx->class_conf_ht); de_ctx->class_conf_ht = NULL; } if (fd != NULL) { fclose(fd); fd = NULL; } if (regex != NULL) { pcre_free(regex); regex = NULL; } if (regex_study != NULL) { pcre_free(regex_study); regex_study = NULL; } return -1; }
/** \brief Create a new LogFileCtx from the provided ConfNode. * \param conf The configuration node for this output. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) { int ret = 0; LogFileCtx* file_ctx = NULL; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Couldn't create new file_ctx"); goto error; } const char *filename = NULL; if (conf != NULL) { /* To faciliate unit tests. */ filename = ConfNodeLookupChildValue(conf, "filename"); } if (filename == NULL) filename = DEFAULT_LOG_FILENAME; file_ctx->prefix = SCStrdup(filename); const char *s_limit = NULL; file_ctx->size_limit = DEFAULT_LIMIT; if (conf != NULL) { s_limit = ConfNodeLookupChildValue(conf, "limit"); if (s_limit != NULL) { if (ParseSizeStringU64(s_limit, &file_ctx->size_limit) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid limit: %s", s_limit); exit(EXIT_FAILURE); } if (file_ctx->size_limit < 4096) { SCLogInfo("unified2-alert \"limit\" value of %"PRIu64" assumed to be pre-1.2 " "style: setting limit to %"PRIu64"mb", file_ctx->size_limit, file_ctx->size_limit); uint64_t size = file_ctx->size_limit * 1024 * 1024; file_ctx->size_limit = size; } else if (file_ctx->size_limit < MIN_LIMIT) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, limit less than " "allowed minimum: %d.", MIN_LIMIT); exit(EXIT_FAILURE); } } } if (conf != NULL) { const char *sensor_id_s = NULL; sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id"); if (sensor_id_s != NULL) { if (ByteExtractStringUint32(&sensor_id, 10, 0, sensor_id_s) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid sensor-id: %s", sensor_id_s); exit(EXIT_FAILURE); } } } ret = Unified2AlertOpenFileCtx(file_ctx, filename); if (ret < 0) goto error; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto error; output_ctx->data = file_ctx; output_ctx->DeInit = Unified2AlertDeInitCtx; SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB", filename, file_ctx->size_limit / (1024*1024)); SC_ATOMIC_INIT(unified2_event_id); return output_ctx; error: if (file_ctx != NULL) { LogFileFreeCtx(file_ctx); } return NULL; }
/** * \internal * \brief Apply the nocase keyword to the last pattern match, either content or uricontent * \param det_ctx detection engine ctx * \param s signature * \param nullstr should be null * \retval 0 ok * \retval -1 failure */ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) { SCEnter(); SigMatch *pm = NULL; int ret = -1; if (nullstr != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "nocase has value"); goto end; } /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs " "preceding content, uricontent option, http_client_body, " "http_server_body, http_header option, http_raw_header option, " "http_method option, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, http_user_agent or " "file_data/dce_stub_data sticky buffer options"); goto end; } /* verify other conditions. */ DetectContentData *cd = (DetectContentData *)pm->ctx;; if (cd->flags & DETECT_CONTENT_NOCASE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple nocase modifiers with the same content"); goto end; } /* for consistency in later use (e.g. by MPM construction and hashing), * coerce the content string to lower-case. */ for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) { *c = u8_tolower(*c); } cd->flags |= DETECT_CONTENT_NOCASE; /* Recreate the context with nocase chars */ SpmDestroyCtx(cd->spm_ctx); cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); if (cd->spm_ctx == NULL) { goto end; } ret = 0; end: SCReturnInt(ret); }
/** * \brief Function to fill unified2 ipv6 ids type format into the file. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param p Packet struct used to decide for ipv4 or ipv6 * \param data Unified2 thread data. * \param pq Packet queue * * \retval 0 on succces * \retval -1 on failure */ int Unified2IPv6TypeAlert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq) { Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader hdr; AlertIPv6Unified2 *phdr = (AlertIPv6Unified2 *)(aun->data + sizeof(Unified2AlertFileHeader)); AlertIPv6Unified2 gphdr; PacketAlert *pa; int offset, length; int ret; unsigned int event_id; if (p->alerts.cnt == 0) return 0; length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv6Unified2)); offset = length; memset(aun->data, 0, aun->datalen); hdr.type = htonl(UNIFIED2_IDS_EVENT_IPV6_TYPE); hdr.length = htonl(sizeof(AlertIPv6Unified2)); /* fill the gphdr structure with the data of the packet */ memset(&gphdr, 0, sizeof(gphdr)); /* FIXME this need to be copied for each alert */ gphdr.sensor_id = htonl(sensor_id); gphdr.event_second = htonl(p->ts.tv_sec); gphdr.event_microsecond = htonl(p->ts.tv_usec); gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p); gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p); gphdr.protocol = p->proto; if(p->action & ACTION_DROP) gphdr.packet_action = UNIFIED2_BLOCKED_FLAG; else gphdr.packet_action = 0; switch(gphdr.protocol) { case IPPROTO_ICMPV6: if(p->icmpv6h) { gphdr.sp = htons(p->icmpv6h->type); gphdr.dp = htons(p->icmpv6h->code); } else { gphdr.sp = 0; gphdr.dp = 0; } break; case IPPROTO_ICMP: if(p->icmpv4h) { gphdr.sp = htons(p->icmpv4h->type); gphdr.dp = htons(p->icmpv4h->code); } else { gphdr.sp = 0; gphdr.dp = 0; } break; case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: gphdr.sp = htons(p->sp); gphdr.dp = htons(p->dp); break; default: gphdr.sp = 0; gphdr.dp = 0; break; } uint16_t i = 0; for (; i < p->alerts.cnt + 1; i++) { if (i < p->alerts.cnt) pa = &p->alerts.alerts[i]; else { if (!(p->flags & PKT_HAS_TAG)) break; pa = PacketAlertGetTag(); } if (unlikely(pa->s == NULL)) continue; /* reset length and offset */ aun->offset = offset; aun->length = length; memset(aun->data + aun->offset, 0, aun->datalen - aun->offset); /* copy the part common to all alerts */ memcpy(aun->data, &hdr, sizeof(hdr)); memcpy(phdr, &gphdr, sizeof(gphdr)); /* fill the header structure with the data of the alert */ event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1)); phdr->event_id = event_id; phdr->generator_id = htonl(pa->s->gid); phdr->signature_id = htonl(pa->s->id); phdr->signature_revision = htonl(pa->s->rev); phdr->classification_id = htonl(pa->s->class); phdr->priority_id = htonl(pa->s->prio); SCMutexLock(&aun->file_ctx->fp_mutex); if ((aun->file_ctx->size_current + length) > aun->file_ctx->size_limit) { if (Unified2AlertRotateFile(t,aun) < 0) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } } if (Unified2Write(aun) != 1) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } memset(aun->data, 0, aun->length); aun->length = 0; aun->offset = 0; ret = Unified2PacketTypeAlert(aun, p, phdr->event_id, pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0); if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } fflush(aun->file_ctx->fp); aun->file_ctx->alerts++; SCMutexUnlock(&aun->file_ctx->fp_mutex); } return 0; }
/** * \brief Function to fill unified2 packet format into the file. If the alert * was generated based on a stream chunk we call the stream function * to generate the record. * * Barnyard2 doesn't like DLT_RAW + IPv6, so if we don't have an ethernet * header, we create a fake one. * * No need to lock here, since it's already locked. * * \param aun thread local data * \param p Packet * \param stream pointer to stream chunk * \param event_id unique event id * \param stream state/stream match, try logging stream segments * * \retval 0 on succces * \retval -1 on failure */ int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int stream) { int ret = 0; /* try stream logging first */ if (stream) { SCLogDebug("logging the state"); uint8_t flag; if (p->flowflags & FLOW_PKT_TOSERVER) { flag = FLOW_PKT_TOCLIENT; } else { flag = FLOW_PKT_TOSERVER; } /* make event id available to callback */ aun->event_id = event_id; /* run callback for all segments in the stream */ ret = StreamSegmentForEach(p, flag, Unified2PrintStreamSegmentCallback, (void *)aun); } /* or no segment could been logged or no segment have been logged */ if (ret == 0) { SCLogDebug("no stream, no state: falling back to payload logging"); Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data); Unified2Packet *phdr = (Unified2Packet *)(hdr + 1); int len = (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE); int datalink = p->datalink; #ifdef HAVE_OLD_BARNYARD2 int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; #endif memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); hdr->type = htonl(UNIFIED2_PACKET_TYPE); aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); phdr->linktype = htonl(datalink); phdr->event_id = event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); aun->phdr = phdr; /* we need to reset offset and length which could * have been modified by the segment logging */ aun->offset = len; len += GET_PKT_LEN(p); aun->length = len; /* Unified 2 packet header is the one of the packet. */ phdr->linktype = htonl(p->datalink); #ifdef HAVE_OLD_BARNYARD2 /* Fake datalink to avoid bug with old barnyard2 */ if (PKT_IS_IPV6(p) && (!p->ethh)) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d", len, aun->datalen - aun->offset); return -1; } ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } #endif if (len > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d", len, aun->datalen - aun->offset); return -1; } hdr->length = htonl(UNIFIED2_PACKET_SIZE + GET_PKT_LEN(p)); phdr->packet_length = htonl(GET_PKT_LEN(p)); memcpy(aun->data + aun->offset, GET_PKT_DATA(p), GET_PKT_LEN(p)); ret = Unified2Write(aun); } if (ret < 1) { return -1; } return 1; }
/** * \brief Write a faked Packet in unified2 file for each stream segment. */ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen) { int ret = 1; Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data); Unified2Packet *phdr = (Unified2Packet *)(hdr + 1); int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; uint32_t hdr_length = 0; int datalink = p->datalink; memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); hdr->type = htonl(UNIFIED2_PACKET_TYPE); aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); phdr->linktype = htonl(datalink); phdr->event_id = aun->event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); aun->phdr = phdr; if (p->datalink != DLT_EN10MB) { /* We have raw data here */ phdr->linktype = htonl(DLT_RAW); datalink = DLT_RAW; } aun->length = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; aun->offset = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; /* Include Packet header */ if (PKT_IS_IPV4(p)) { FakeIPv4Hdr fakehdr; hdr_length = sizeof(FakeIPv4Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IP); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); aun->length += hdr_length; Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0); if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else if (PKT_IS_IPV6(p)) { FakeIPv6Hdr fakehdr; hdr_length = sizeof(FakeIPv6Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); Unified2ForgeFakeIPv6Header(&fakehdr, p, buflen, 1); aun->length += hdr_length; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else { goto error; } /* update unified2 headers for length */ aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset + hdr_length + buflen); aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen); /* copy stream segment payload in */ aun->length += buflen; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread" " data: %d vs %d", aun->length, aun->datalen); goto error; } memcpy(aun->data + aun->offset, buf, buflen); aun->offset += buflen; /* rebuild checksum */ if (PKT_IS_IPV6(p)) { FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); } /* write out */ ret = Unified2Write(aun); if (ret != 1) { goto error; } return 1; error: aun->length = 0; aun->offset = 0; return -1; }
TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) { #ifndef OS_WIN32 struct timeval tv; int opt; #endif NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index); if (nfq_q == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index"); return TM_ECODE_FAILED; } SCLogDebug("opening library handle"); nfq_q->h = nfq_open(); if (!nfq_q->h) { SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed"); return TM_ECODE_FAILED; } if (nfq_g.unbind == 0) { /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } nfq_g.unbind = 1; SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6"); if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } } SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num); /* pass the thread memory as a void ptr so the * callback function has access to it. */ nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t); if (nfq_q->qh == NULL) { SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed"); return TM_ECODE_FAILED; } SCLogDebug("setting copy_packet mode"); /* 05DC = 1500 */ //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode"); return TM_ECODE_FAILED; } #ifdef HAVE_NFQ_MAXLEN if (queue_maxlen > 0) { SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen); /* non-fatal if it fails */ if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) { SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably " "doesn't support setting the queue length"); } } #endif /* HAVE_NFQ_MAXLEN */ #ifndef OS_WIN32 /* set netlink buffer size to a decent value */ nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500); SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500); nfq_q->nh = nfq_nfnlh(nfq_q->h); nfq_q->fd = nfnl_fd(nfq_q->nh); NFQMutexInit(nfq_q); /* Set some netlink specific option on the socket to increase performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR if (setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink broadcast error: %s", strerror(errno)); } #endif /* Don't send error about no buffer space available but drop the packets instead */ #ifdef NETLINK_NO_ENOBUFS if (setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink enobufs: %s", strerror(errno)); } #endif #ifdef HAVE_NFQ_SET_QUEUE_FLAGS if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) { uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; int r = nfq_set_queue_flags(nfq_q->qh, mask, flags); if (r == -1) { SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s", strerror(errno)); } else { SCLogInfo("fail-open mode should be set on queue"); } } #endif #ifdef HAVE_NFQ_SET_VERDICT_BATCH if (runmode_workers) { nfq_q->verdict_cache.maxlen = nfq_config.batchcount; } else if (nfq_config.batchcount) { SCLogError(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount is only valid in workers runmode."); } #endif /* set a timeout to the socket so we can check for a signal * in case we don't get packets for a longer period. */ tv.tv_sec = 1; tv.tv_usec = 0; if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno)); } SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd); #else /* OS_WIN32 */ NFQMutexInit(nfq_q); nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); nfq_q->fd = nfq_fd(nfq_q->h); SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd); #endif /* OS_WIN32 */ return TM_ECODE_OK; }
int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { if (!(AppLayerParserIsTxAware(alproto))) { SCLogNotice("%s logger not enabled: protocol %s is disabled", name, AppProtoToString(alproto)); return -1; } OutputTxLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; memset(op, 0x00, sizeof(*op)); op->alproto = alproto; op->LogFunc = LogFunc; op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; op->logger_id = id; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; if (tc_log_progress < 0) { op->tc_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); } else { op->tc_log_progress = tc_log_progress; } if (ts_log_progress < 0) { op->ts_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); } else { op->ts_log_progress = ts_log_progress; } if (list == NULL) { op->id = 1; list = op; } else { OutputTxLogger *t = list; while (t->next) t = t->next; if (t->id * 2 > UINT32_MAX) { SCLogError(SC_ERR_FATAL, "Too many loggers registered."); exit(EXIT_FAILURE); } op->id = t->id * 2; t->next = op; } SCLogDebug("OutputRegisterTxLogger happy"); return 0; }
TmEcode NoNFQSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_NFQ_NOSUPPORT,"Error creating thread %s: you do not have support for nfqueue " "enabled please recompile with --enable-nfqueue", tv->name); exit(EXIT_FAILURE); }
static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_msg\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_stat_msg\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_stat_msg should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg seen with a " "distance or within without a previous http_stat_msg " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSMDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HSMDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; }
/** * \internal * \brief This function is used to parse detection_filter options passed via detection_filter: keyword * * \param rawstr Pointer to the user provided detection_filter options * * \retval df pointer to DetectThresholdData on success * \retval NULL on failure */ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) { DetectThresholdData *df = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *args[6] = { NULL, NULL, NULL, NULL, NULL, NULL}; char *copy_str = NULL, *df_opt = NULL; int seconds_found = 0, count_found = 0, track_found = 0; int seconds_pos = 0, count_pos = 0; uint16_t pos = 0; int i = 0; copy_str = SCStrdup(rawstr); if (unlikely(copy_str == NULL)) { goto error; } for(pos = 0, df_opt = strtok(copy_str,","); pos < strlen(copy_str) && df_opt != NULL; pos++, df_opt = strtok(NULL,",")) { if(strstr(df_opt,"count")) count_found++; if(strstr(df_opt,"second")) seconds_found++; if(strstr(df_opt,"track")) track_found++; } SCFree(copy_str); copy_str = NULL; if (count_found != 1 || seconds_found != 1 || track_found != 1) goto error; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 5) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } df = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(df == NULL)) goto error; memset(df,0,sizeof(DetectThresholdData)); df->type = TYPE_DETECTION; for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0) df->track = TRACK_DST; if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0) df->track = TRACK_SRC; if (strncasecmp(args[i],"count",strlen("count")) == 0) count_pos = i+1; if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0) seconds_pos = i+1; } if (args[count_pos] == NULL || args[seconds_pos] == NULL) { goto error; } if (ByteExtractStringUint32(&df->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) { goto error; } if (ByteExtractStringUint32(&df->seconds, 10, strlen(args[seconds_pos]), args[seconds_pos]) <= 0) { goto error; } if (df->count == 0 || df->seconds == 0) { SCLogError(SC_ERR_INVALID_VALUE, "found an invalid value"); goto error; } for (i = 0; i < 6; i++){ if (args[i] != NULL) SCFree(args[i]); } return df; error: for (i = 0; i < 6; i++){ if (args[i] != NULL) SCFree(args[i]); } if (df != NULL) SCFree(df); return NULL; }
static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFlowvarData *cd = NULL; SigMatch *sm = NULL; char *str = rawstr; char dubbed = 0; uint16_t len; char *varname = NULL, *varcontent = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowvar.", rawstr); return -1; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varname = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varcontent = (char *)str_ptr; } if (varcontent[0] == '\"' && varcontent[strlen(varcontent)-1] == '\"') { str = SCStrdup(varcontent+1); str[strlen(varcontent)-2] = '\0'; dubbed = 1; } len = strlen(str); if (len == 0) { if (dubbed) SCFree(str); return -1; } cd = SCMalloc(sizeof(DetectFlowvarData)); if (cd == NULL) goto error; char converted = 0; { uint16_t i, x; uint8_t bin = 0, binstr[3] = "", binpos = 0; for (i = 0, x = 0; i < len; i++) { // printf("str[%02u]: %c\n", i, str[i]); if (str[i] == '|') { if (bin) { bin = 0; } else { bin = 1; } } else { if (bin) { if (isdigit(str[i]) || str[i] == 'A' || str[i] == 'a' || str[i] == 'B' || str[i] == 'b' || str[i] == 'C' || str[i] == 'c' || str[i] == 'D' || str[i] == 'd' || str[i] == 'E' || str[i] == 'e' || str[i] == 'F' || str[i] == 'f') { // printf("part of binary: %c\n", str[i]); binstr[binpos] = (char)str[i]; binpos++; if (binpos == 2) { uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; binpos = 0; str[x] = c; x++; converted = 1; } } else if (str[i] == ' ') { // printf("space as part of binary string\n"); } } else { str[x] = str[i]; x++; } } } #ifdef DEBUG if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { if (isprint(str[i])) printf("%c", str[i]); else printf("\\x%02u", str[i]); } printf("\n"); } #endif if (converted) len = x; } cd->content = SCMalloc(len); if (cd->content == NULL) { if (dubbed) SCFree(str); SCFree(cd); return -1; } cd->name = SCStrdup(varname); cd->idx = VariableNameGetIdx(varname,DETECT_FLOWVAR); memcpy(cd->content, str, len); cd->content_len = len; cd->flags = 0; /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLOWVAR; sm->ctx = (void *)cd; SigMatchAppendPacket(s, sm); if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); if (cd) SCFree(cd); if (sm) SCFree(sm); return -1; }
TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); char *tmpbpfstring = NULL; char *tmpstring = NULL; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("reading pcap file %s", (char *)initdata); PcapFileThreadVars *ptv = SCMalloc(sizeof(PcapFileThreadVars)); if (unlikely(ptv == NULL)) SCReturnInt(TM_ECODE_FAILED); memset(ptv, 0, sizeof(PcapFileThreadVars)); intmax_t tenant = 0; if (ConfGetInt("pcap-file.tenant-id", &tenant) == 1) { if (tenant > 0 && tenant < UINT_MAX) { ptv->tenant_id = (uint32_t)tenant; SCLogInfo("tenant %u", ptv->tenant_id); } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant out of range"); } } char errbuf[PCAP_ERRBUF_SIZE] = ""; pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf); if (pcap_g.pcap_handle == NULL) { SCLogError(SC_ERR_FOPEN, "%s\n", errbuf); SCFree(ptv); if (! RunModeUnixSocketIsActive()) { return TM_ECODE_FAILED; } else { UnixSocketPcapFile(TM_ECODE_FAILED); SCReturnInt(TM_ECODE_DONE); } } if (ConfGet("bpf-filter", &tmpbpfstring) != 1) { SCLogDebug("could not get bpf or none specified"); } else { SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring); if (pcap_compile(pcap_g.pcap_handle, &pcap_g.filter, tmpbpfstring, 1, 0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s", pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } if (pcap_setfilter(pcap_g.pcap_handle, &pcap_g.filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s", pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } } pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle); SCLogDebug("datalink %" PRId32 "", pcap_g.datalink); switch (pcap_g.datalink) { case LINKTYPE_LINUX_SLL: pcap_g.Decoder = DecodeSll; break; case LINKTYPE_ETHERNET: pcap_g.Decoder = DecodeEthernet; break; case LINKTYPE_PPP: pcap_g.Decoder = DecodePPP; break; case LINKTYPE_RAW: pcap_g.Decoder = DecodeRaw; break; case LINKTYPE_NULL: pcap_g.Decoder = DecodeNull; break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not " "(yet) supported in module PcapFile.\n", pcap_g.datalink); SCFree(ptv); if (! RunModeUnixSocketIsActive()) { SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } if (ConfGet("pcap-file.checksum-checks", &tmpstring) != 1) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; } else { if (strcmp(tmpstring, "auto") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpstring, "yes") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpstring, "no") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE; } } pcap_g.checksum_mode = pcap_g.conf_checksum_mode; ptv->tv = tv; *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); }
/* JSON format logging */ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) { #if 0 LogJsonFileCtx *flow_ctx = aft->flowlog_ctx; #endif json_t *hjs = json_object(); if (hjs == NULL) { return; } json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto))); if (f->alproto_ts != f->alproto) { json_object_set_new(js, "app_proto_ts", json_string(AppProtoToString(f->alproto_ts))); } if (f->alproto_tc != f->alproto) { json_object_set_new(js, "app_proto_tc", json_string(AppProtoToString(f->alproto_tc))); } json_object_set_new(hjs, "pkts_toserver", json_integer(f->todstpktcnt)); json_object_set_new(hjs, "pkts_toclient", json_integer(f->tosrcpktcnt)); json_object_set_new(hjs, "bytes_toserver", json_integer(f->todstbytecnt)); json_object_set_new(hjs, "bytes_toclient", json_integer(f->tosrcbytecnt)); char timebuf1[64], timebuf2[64]; CreateIsoTimeString(&f->startts, timebuf1, sizeof(timebuf1)); CreateIsoTimeString(&f->lastts, timebuf2, sizeof(timebuf2)); json_object_set_new(hjs, "start", json_string(timebuf1)); json_object_set_new(hjs, "end", json_string(timebuf2)); int32_t age = f->lastts.tv_sec - f->startts.tv_sec; json_object_set_new(hjs, "age", json_integer(age)); if (f->flow_end_flags & FLOW_END_FLAG_EMERGENCY) json_object_set_new(hjs, "emergency", json_true()); const char *state = NULL; if (f->flow_end_flags & FLOW_END_FLAG_STATE_NEW) state = "new"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_ESTABLISHED) state = "established"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED) state = "closed"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) { state = "bypassed"; int flow_state = SC_ATOMIC_GET(f->flow_state); switch (flow_state) { case FLOW_STATE_LOCAL_BYPASSED: json_object_set_new(hjs, "bypass", json_string("local")); break; case FLOW_STATE_CAPTURE_BYPASSED: json_object_set_new(hjs, "bypass", json_string("capture")); break; default: SCLogError(SC_ERR_INVALID_VALUE, "Invalid flow state: %d, contact developers", flow_state); } } json_object_set_new(hjs, "state", json_string(state)); const char *reason = NULL; if (f->flow_end_flags & FLOW_END_FLAG_TIMEOUT) reason = "timeout"; else if (f->flow_end_flags & FLOW_END_FLAG_FORCED) reason = "forced"; else if (f->flow_end_flags & FLOW_END_FLAG_SHUTDOWN) reason = "shutdown"; json_object_set_new(hjs, "reason", json_string(reason)); json_object_set_new(js, "flow", hjs); /* TCP */ if (f->proto == IPPROTO_TCP) { json_t *tjs = json_object(); if (tjs == NULL) { return; } TcpSession *ssn = f->protoctx; char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->tcp_packet_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->client.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags_ts", json_string(hexflags)); snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->server.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags_tc", json_string(hexflags)); JsonTcpFlags(ssn ? ssn->tcp_packet_flags : 0, tjs); if (ssn) { char *tcp_state = NULL; switch (ssn->state) { case TCP_NONE: tcp_state = "none"; break; case TCP_LISTEN: tcp_state = "listen"; break; case TCP_SYN_SENT: tcp_state = "syn_sent"; break; case TCP_SYN_RECV: tcp_state = "syn_recv"; break; case TCP_ESTABLISHED: tcp_state = "established"; break; case TCP_FIN_WAIT1: tcp_state = "fin_wait1"; break; case TCP_FIN_WAIT2: tcp_state = "fin_wait2"; break; case TCP_TIME_WAIT: tcp_state = "time_wait"; break; case TCP_LAST_ACK: tcp_state = "last_ack"; break; case TCP_CLOSE_WAIT: tcp_state = "close_wait"; break; case TCP_CLOSING: tcp_state = "closing"; break; case TCP_CLOSED: tcp_state = "closed"; break; } json_object_set_new(tjs, "state", json_string(tcp_state)); } json_object_set_new(js, "tcp", tjs); } }
/** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * \return a NetmapIfaceConfig corresponding to the interface name */ static void *ParseNetmapConfig(const char *iface_name) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *netmap_node; char *tmpctype; char *copymodestr; int boolval; char *bpf_filter = NULL; char *out_iface = NULL; if (iface_name == NULL) { return NULL; } NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); if (unlikely(aconf == NULL)) { return NULL; } memset(aconf, 0, sizeof(*aconf)); aconf->DerefFunc = NetmapDerefConfig; aconf->threads = 0; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; aconf->copy_mode = NETMAP_COPY_MODE_NONE; strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); strlcpy(aconf->iface, aconf->iface_name, sizeof(aconf->iface)); if (aconf->iface[0]) { size_t len = strlen(aconf->iface); if (aconf->iface[len-1] == '+') { aconf->iface[len-1] = '\0'; aconf->iface_sw = 1; } } if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } /* Find initial node */ netmap_node = ConfGetNode("netmap"); if (netmap_node == NULL) { SCLogInfo("Unable to find netmap config using default value"); goto finalize; } if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); if_default = ConfFindDeviceConfig(netmap_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " "interface \"%s\" or \"default\", using default value", aconf->iface_name); goto finalize; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { aconf->threads = 0; } else { if (strcmp(threadsstr, "auto") == 0) { aconf->threads = 0; } else { aconf->threads = (uint8_t)atoi(threadsstr); } } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { aconf->out_iface_name = out_iface; } } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (aconf->out_iface_name == NULL) { SCLogInfo("Copy mode activated but no destination" " iface. Disabling feature"); } else if (strlen(copymodestr) <= 0) { aconf->out_iface_name = NULL; } else if (strcmp(copymodestr, "ips") == 0) { SCLogInfo("Netmap IPS mode activated %s->%s", aconf->iface_name, aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { SCLogInfo("Netmap TAP mode activated %s->%s", aconf->iface_name, aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_TAP; } else { SCLogInfo("Invalid mode (not in tap, ips)"); } } if (aconf->out_iface_name && aconf->out_iface_name[0]) { strlcpy(aconf->out_iface, aconf->out_iface_name, sizeof(aconf->out_iface)); size_t len = strlen(aconf->out_iface); if (aconf->out_iface[len-1] == '+') { aconf->out_iface[len-1] = '\0'; aconf->out_iface_sw = 1; } } /* load netmap bpf filter */ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); } } } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name); } } finalize: if (aconf->iface_sw) { /* just one thread per interface supported */ aconf->threads = 1; } else if (aconf->threads == 0) { /* As NetmapGetRSSCount is broken on Linux, first run * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); if (aconf->threads == 0) { aconf->threads = NetmapGetRSSCount(aconf->iface); } } if (aconf->threads <= 0) { aconf->threads = 1; } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); SCLogPerf("Using %d threads for interface %s", aconf->threads, aconf->iface_name); return aconf; }
/** * \brief This function is used to parse icode options passed via icode: keyword * * \param icodestr Pointer to the user provided icode options * * \retval icd pointer to DetectICodeData on success * \retval NULL on failure */ DetectICodeData *DetectICodeParse(char *icodestr) { DetectICodeData *icd = NULL; char *args[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, icodestr, strlen(icodestr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, icodestr); goto error; } int i; const char *str_ptr; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)icodestr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i-1] = (char *)str_ptr; } icd = SCMalloc(sizeof(DetectICodeData)); if (icd == NULL) goto error; icd->code1 = 0; icd->code2 = 0; icd->mode = 0; /* we have either "<" or ">" */ if (args[0] != NULL && strlen(args[0]) != 0) { /* we have a third part ("<> y"), therefore it's invalid */ if (args[2] != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "icode: invalid value"); goto error; } /* we have only a comparison ("<", ">") */ if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } if ((strcmp(args[0], ">")) == 0) icd->mode = DETECT_ICODE_GT; else icd->mode = DETECT_ICODE_LT; } else { /* no "<", ">" */ /* we have a range ("<>") */ if (args[2] != NULL) { icd->mode = (uint8_t) DETECT_ICODE_RN; if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } if (ByteExtractStringUint8(&icd->code2, 10, 0, args[2]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[2]); goto error; } /* we check that the first given value in the range is less than the second, otherwise we swap them */ if (icd->code1 > icd->code2) { uint8_t temp = icd->code1; icd->code1 = icd->code2; icd->code2 = temp; } } else { /* we have an equality */ icd->mode = DETECT_ICODE_EQ; if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } } } for (i = 0; i < (ret-1); i++) { if (args[i] != NULL) SCFree(args[i]); } return icd; error: for (i = 0; i < (ret-1) && i < 3; i++) { if (args[i] != NULL) SCFree(args[i]); } if (icd != NULL) DetectICodeFree(icd); return NULL; }
static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) { char *str = NULL; uint16_t len; if (strlen(msgstr) == 0) goto error; /* strip "'s */ if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { str = SCStrdup(msgstr+1); if (unlikely(str == NULL)) goto error; str[strlen(msgstr)-2] = '\0'; } else if (msgstr[1] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { /* XXX do this parsing in a better way */ str = SCStrdup(msgstr+2); if (unlikely(str == NULL)) goto error; str[strlen(msgstr)-3] = '\0'; //printf("DetectMsgSetup: format hack applied: \'%s\'\n", str); } else { SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr); goto error; } len = strlen(str); if (len == 0) goto error; char converted = 0; { uint16_t i, x; uint8_t escape = 0; /* it doesn't matter if we need to escape or not we remove the extra "\" to mimic snort */ for (i = 0, x = 0; i < len; i++) { //printf("str[%02u]: %c\n", i, str[i]); if(!escape && str[i] == '\\') { escape = 1; } else if (escape) { if (str[i] != ':' && str[i] != ';' && str[i] != '\\' && str[i] != '\"') { SCLogDebug("character \"%c\" does not need to be escaped but is" ,str[i]); } escape = 0; converted = 1; str[x] = str[i]; x++; }else{ str[x] = str[i]; x++; } } #if 0 //def DEBUG if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { printf("%c", str[i]); } printf("\n"); } #endif if (converted) { len = x; str[len] = '\0'; } } s->msg = SCMalloc(len + 1); if (s->msg == NULL) goto error; strlcpy(s->msg, str, len + 1); SCFree(str); return 0; error: SCFree(str); return -1; }
DetectTtlData *DetectTtlParse (char *ttlstr) { DetectTtlData *ttld = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, ttlstr, strlen(ttlstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); goto error; } const char *str_ptr; res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); if (ret >= 3) { res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret >= 4) { res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); } } ttld = SCMalloc(sizeof (DetectTtlData)); if (unlikely(ttld == NULL)) goto error; ttld->ttl1 = 0; ttld->ttl2 = 0; if (arg2 != NULL) { /*set the values*/ switch(arg2[0]) { case '<': if (arg3 == NULL) goto error; ttld->mode = DETECT_TTL_LT; ttld->ttl1 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8"",ttld->ttl1); if (strlen(arg1) > 0) goto error; break; case '>': if (arg3 == NULL) goto error; ttld->mode = DETECT_TTL_GT; ttld->ttl1 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8"",ttld->ttl1); if (strlen(arg1) > 0) goto error; break; case '-': if (arg1 == NULL || strlen(arg1)== 0) goto error; if (arg3 == NULL || strlen(arg3)== 0) goto error; ttld->mode = DETECT_TTL_RA; ttld->ttl1 = (uint8_t) atoi(arg1); ttld->ttl2 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8" to %"PRIu8"",ttld->ttl1, ttld->ttl2); if (ttld->ttl1 >= ttld->ttl2) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid ttl range. "); goto error; } break; default: ttld->mode = DETECT_TTL_EQ; if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); break; } } else { ttld->mode = DETECT_TTL_EQ; if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); } SCFree(arg1); SCFree(arg2); SCFree(arg3); return ttld; error: if (ttld) SCFree(ttld); if (arg1) SCFree(arg1); if (arg2) SCFree(arg2); if (arg3) SCFree(arg3); return NULL; }
/** * \internal * \brief Function to parse options passed via tls validity keywords. * * \param rawstr Pointer to the user provided options. * * \retval dd pointer to DetectNfsVersionData on success. * \retval NULL on failure. */ static DetectNfsVersionData *DetectNfsVersionParse (const char *rawstr) { DetectNfsVersionData *dd = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; char mode[2] = ""; char value1[20] = ""; char value2[20] = ""; char range[3] = ""; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 5) { SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", rawstr); goto error; } res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode, sizeof(mode)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } SCLogDebug("mode \"%s\"", mode); res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1, sizeof(value1)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } SCLogDebug("value1 \"%s\"", value1); if (ret > 3) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, range, sizeof(range)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } SCLogDebug("range \"%s\"", range); if (ret > 4) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, value2, sizeof(value2)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } SCLogDebug("value2 \"%s\"", value2); } } dd = SCCalloc(1, sizeof(DetectNfsVersionData)); if (unlikely(dd == NULL)) goto error; if (strlen(mode) == 1) { if (mode[0] == '<') dd->mode = PROCEDURE_LT; else if (mode[0] == '>') dd->mode = PROCEDURE_GT; } else if (strlen(mode) == 2) { if (strcmp(mode, "<=") == 0) dd->mode = PROCEDURE_LE; if (strcmp(mode, ">=") == 0) dd->mode = PROCEDURE_GE; } if (strlen(range) > 0) { if (strcmp("<>", range) == 0) dd->mode = PROCEDURE_RA; } if (strlen(range) != 0 && strlen(mode) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Range specified but mode also set"); goto error; } if (dd->mode == 0) { dd->mode = PROCEDURE_EQ; } /* set the first value */ dd->lo = atoi(value1); //TODO /* set the second value if specified */ if (strlen(value2) > 0) { if (!(dd->mode == PROCEDURE_RA)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Multiple tls validity values specified but mode is not range"); goto error; } // dd->hi = atoi(value2); // TODO if (dd->hi <= dd->lo) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Second value in range must not be smaller than the first"); goto error; } } return dd; error: if (dd) SCFree(dd); return NULL; }
/** \brief To initialize the NFQ global configuration data * * \param quiet It tells the mode of operation, if it is TRUE nothing will * be get printed. */ void NFQInitConfig(char quiet) { intmax_t value = 0; char* nfq_mode = NULL; int boolval; SCLogDebug("Initializing NFQ"); memset(&nfq_config, 0, sizeof(nfq_config)); if ((ConfGet("nfq.mode", &nfq_mode)) == 0) { nfq_config.mode = NFQ_ACCEPT_MODE; } else { if (!strcmp("accept", nfq_mode)) { nfq_config.mode = NFQ_ACCEPT_MODE; } else if (!strcmp("repeat", nfq_mode)) { nfq_config.mode = NFQ_REPEAT_MODE; } else if (!strcmp("route", nfq_mode)) { nfq_config.mode = NFQ_ROUTE_MODE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown nfq.mode"); exit(EXIT_FAILURE); } } (void)ConfGetBool("nfq.fail-open", (int *)&boolval); if (boolval) { #ifdef HAVE_NFQ_SET_QUEUE_FLAGS SCLogInfo("Enabling fail-open on queue"); nfq_config.flags |= NFQ_FLAG_FAIL_OPEN; #else SCLogError(SC_ERR_NFQ_NOSUPPORT, "nfq.%s set but NFQ library has no support for it.", "fail-open"); #endif } if ((ConfGetInt("nfq.repeat-mark", &value)) == 1) { nfq_config.mark = (uint32_t)value; } if ((ConfGetInt("nfq.repeat-mask", &value)) == 1) { nfq_config.mask = (uint32_t)value; } if ((ConfGetInt("nfq.route-queue", &value)) == 1) { nfq_config.next_queue = ((uint32_t)value) << 16; } if ((ConfGetInt("nfq.batchcount", &value)) == 1) { #ifdef HAVE_NFQ_SET_VERDICT_BATCH if (value > 255) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount cannot exceed 255."); value = 255; } if (value > 1) nfq_config.batchcount = (uint8_t) (value - 1); #else SCLogWarning(SC_ERR_NFQ_NOSUPPORT, "nfq.%s set but NFQ library has no support for it.", "batchcount"); #endif } if (!quiet) { switch (nfq_config.mode) { case NFQ_ACCEPT_MODE: SCLogInfo("NFQ running in standard ACCEPT/DROP mode"); break; case NFQ_REPEAT_MODE: SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32, nfq_config.mark, nfq_config.mask); break; case NFQ_ROUTE_MODE: SCLogInfo("NFQ running in route mode with next queue %"PRIu32, nfq_config.next_queue); break; } } }
int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) { char tname[16]; ThreadVars *tv = NULL; TmModule *tm_module = NULL; char *cur_queue = NULL; int nqueue = LiveGetDeviceCount(); for (int i = 0; i < nqueue; i++) { /* create the threads */ cur_queue = LiveGetDeviceName(i); if (cur_queue == NULL) { printf("ERROR: Invalid queue number\n"); exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue); char *thread_name = SCStrdup(tname); tv = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv, tm_module, (void *)de_ctx, de_ctx->delayed_detect); tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); SetupOutputs(tv); TmThreadSetCPU(tv, DETECT_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } return 0; }
/** * \brief Init function for RecievePfring. * * This is a setup function for recieving packets * via libpfring. * * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with PfringThreadVars * \todo add a config option for setting cluster id * \todo Create a general pfring setup function. * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on error */ TmEcode ReceivePfringThreadInit(ThreadVars *tv, const void *initdata, void **data) { int rc; u_int32_t version = 0; PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; unsigned int opflag; char const *active_runmode = RunmodeGetActive(); if (pfconf == NULL) return TM_ECODE_FAILED; PfringThreadVars *ptv = SCMalloc(sizeof(PfringThreadVars)); if (unlikely(ptv == NULL)) { pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } memset(ptv, 0, sizeof(PfringThreadVars)); ptv->tv = tv; ptv->threads = 1; ptv->interface = SCStrdup(pfconf->iface); if (unlikely(ptv->interface == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate device string"); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } ptv->livedev = LiveGetDevice(pfconf->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } /* enable zero-copy mode for workers runmode */ if (active_runmode && strcmp("workers", active_runmode) == 0) { ptv->flags |= PFRING_FLAGS_ZERO_COPY; SCLogPerf("Enabling zero-copy for %s", ptv->interface); } ptv->checksum_mode = pfconf->checksum_mode; opflag = PF_RING_PROMISC; /* if suri uses VLAN and if we have a recent kernel, we need * to use parsed_pkt to get VLAN info */ if ((! ptv->vlan_disabled) && SCKernelVersionIsAtLeast(3, 0)) { opflag |= PF_RING_LONG_HEADER; } if (ptv->checksum_mode == CHECKSUM_VALIDATION_RXONLY) { if (strncmp(ptv->interface, "dna", 3) == 0) { SCLogWarning(SC_ERR_INVALID_VALUE, "Can't use rxonly checksum-checks on DNA interface," " resetting to auto"); ptv->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else { opflag |= PF_RING_LONG_HEADER; } } #ifdef HAVE_PF_RING_FLOW_OFFLOAD if (pfconf->flags & PFRING_CONF_FLAGS_BYPASS) { opflag |= PF_RING_FLOW_OFFLOAD | PF_RING_FLOW_OFFLOAD_NOUPDATES; ptv->flags |= PFRING_FLAGS_BYPASS; } #endif ptv->pd = pfring_open(ptv->interface, (uint32_t)default_packet_size, opflag); if (ptv->pd == NULL) { SCLogError(SC_ERR_PF_RING_OPEN,"Failed to open %s: pfring_open error." " Check if %s exists and pf_ring module is loaded.", ptv->interface, ptv->interface); pfconf->DerefFunc(pfconf); SCFree(ptv); return TM_ECODE_FAILED; } pfring_set_application_name(ptv->pd, (char *)PROG_NAME); pfring_version(ptv->pd, &version); /* We only set cluster info if the number of pfring threads is greater than 1 */ ptv->threads = pfconf->threads; ptv->cluster_id = pfconf->cluster_id; if ((ptv->threads == 1) && (strncmp(ptv->interface, "dna", 3) == 0)) { SCLogInfo("DNA interface detected, not adding thread to cluster"); } else if (strncmp(ptv->interface, "zc", 2) == 0) { SCLogInfo("ZC interface detected, not adding thread to cluster"); } else { ptv->ctype = (cluster_type)pfconf->ctype; rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, ptv->ctype); if (rc != 0) { SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " "returned %d for cluster-id: %d", rc, ptv->cluster_id); if (rc != PF_RING_ERROR_NOT_SUPPORTED || (pfconf->flags & PFRING_CONF_FLAGS_CLUSTER)) { /* cluster is mandatory as explicitly specified in the configuration */ pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } } } if (ptv->threads > 1) { SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } else {